¿Llegar a UIViewController desde UIView?

Resuelto bertrandom asked hace 54 años • 30 respuestas

¿ Existe una forma integrada de llegar de a UIViewa su UIViewController? Sé que puedes acceder UIViewControllera su UIViewvía [self view], pero me preguntaba si hay una referencia inversa.

bertrandom avatar Jan 01 '70 08:01 bertrandom
Aceptado

Usando el ejemplo publicado por Brock, lo modifiqué para que sea una categoría de UIView en lugar de UIViewController y lo hice recursivo para que cualquier subvista pueda (con suerte) encontrar el UIViewController principal.

@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
@end

@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
    UIResponder *responder = [self nextResponder];
    while (responder != nil) {
        if ([responder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)responder;
        }
        responder = [responder nextResponder];
    }
    return nil;
}

@end

Para usar este código, agréguelo a un nuevo archivo de clase (yo llamé al mío "UIKitCategories") y elimine los datos de la clase... copie @interface en el encabezado y @implementation en el archivo .m. Luego, en su proyecto, #importe "UIKitCategories.h" y utilícelo dentro del código UIView:

// from a UIView subclass... returns nil if UIViewController not available
UIViewController * myController = [self firstAvailableUIViewController];
Phil M avatar Sep 17 '2010 05:09 Phil M

UIViewes una subclase de UIResponder. UIResponderpresenta el método -nextRespondercon una implementación que devuelve nil. UIViewanula este método, como se documenta en UIResponder(por alguna razón en lugar de en UIView) de la siguiente manera: si la vista tiene un controlador de vista, lo devuelve -nextResponder. Si no hay un controlador de vista, el método devolverá la supervisión.

Agregue esto a su proyecto y estará listo para comenzar.

@interface UIView (APIFix)
- (UIViewController *)viewController;
@end

@implementation UIView (APIFix)

- (UIViewController *)viewController {
    if ([self.nextResponder isKindOfClass:UIViewController.class])
        return (UIViewController *)self.nextResponder;
    else
        return nil;
}
@end

Ahora UIViewtiene un método de trabajo para devolver el controlador de vista.

Brock avatar Apr 07 '2010 23:04 Brock

Dado que esta ha sido la respuesta aceptada durante mucho tiempo, siento que necesito rectificarla con una respuesta mejor.

Algunos comentarios sobre la necesidad:

  • Su vista no debería necesitar acceder directamente al controlador de vista.
  • En cambio, la vista debería ser independiente del controlador de vista y poder funcionar en diferentes contextos.
  • Si necesita que la vista interactúe de alguna manera con el controlador de vista, la forma recomendada, y lo que Apple hace en Cocoa es usar el patrón de delegado.

A continuación se muestra un ejemplo de cómo implementarlo:

@protocol MyViewDelegate < NSObject >

- (void)viewActionHappened;

@end

@interface MyView : UIView

@property (nonatomic, assign) MyViewDelegate delegate;

@end

@interface MyViewController < MyViewDelegate >

@end

La vista interactúa con su delegado (como UITableViewlo hace, por ejemplo) y no le importa si está implementada en el controlador de vista o en cualquier otra clase que termine usando.

Mi respuesta original es la siguiente: No recomiendo esto, ni el resto de respuestas donde se logra acceso directo al controlador de vista.

No existe una forma integrada de hacerlo. Si bien puede solucionarlo agregando un IBOutlety UIViewconectándolos en Interface Builder, no se recomienda. La vista no debe conocer el controlador de vista. En su lugar, debe hacer lo que sugiere @Phil M y crear un protocolo para usarlo como delegado.

pgb avatar Aug 27 '2009 11:08 pgb

Yo sugeriría un enfoque más ligero para recorrer la cadena de respuesta completa sin tener que agregar una categoría en UIView:

@implementation MyUIViewSubclass

- (UIViewController *)viewController {
    UIResponder *responder = self;
    while (![responder isKindOfClass:[UIViewController class]]) {
        responder = [responder nextResponder];
        if (nil == responder) {
            break;
        }
    }
    return (UIViewController *)responder;
}

@end
de. avatar Jan 26 '2012 22:01 de.