¿Hay una forma integrada de llegar de a UIView
a su UIViewController
? Sé que puede llegar UIViewController
a su UIView
vía, [self view]
pero me preguntaba si hay una referencia inversa.
fuente
¿Hay una forma integrada de llegar de a UIView
a su UIViewController
? Sé que puede llegar UIViewController
a su UIView
vía, [self view]
pero me preguntaba si hay una referencia inversa.
Como esta ha sido la respuesta aceptada durante mucho tiempo, siento que necesito rectificarla con una respuesta mejor.
Algunos comentarios sobre la necesidad:
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 lo UITableView
hace, por ejemplo) y no le importa si se implementa en el controlador de vista o en cualquier otra clase que termine usando.
Mi respuesta original sigue: no recomiendo esto, ni el resto de las respuestas donde se logra el acceso directo al controlador de vista
No hay una forma integrada de hacerlo. Mientras que usted puede conseguir alrededor de él mediante la adición de una IBOutlet
sobre la UIView
y la conexión de estos en Interface Builder, esto no es recomendable. La vista no debe saber sobre el controlador de vista. En su lugar, debe hacer lo que @Phil M sugiere y crear un protocolo para usar como delegado.
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 padre.
Para usar este código, agréguelo a un nuevo archivo de clase (llamé al mío "UIKitCategories") y elimine los datos de la clase ... copie la @interface en el encabezado y la @implementation en el archivo .m. Luego, en su proyecto, # importe "UIKitCategories.h" y use dentro del código UIView:
fuente
UIView
es una subclase deUIResponder
.UIResponder
presenta el método-nextResponder
con una implementación que devuelvenil
.UIView
anula este método, como se documenta enUIResponder
(por alguna razón en lugar de enUIView
) de la siguiente manera: si la vista tiene un controlador de vista, es devuelta por-nextResponder
. Si no hay un controlador de vista, el método devolverá la supervista.Agregue esto a su proyecto y estará listo para comenzar.
Ahora
UIView
tiene un método de trabajo para devolver el controlador de vista.fuente
UIView
y elUIViewController
. La respuesta de Phil M con recursión es el camino a seguir.Sugeriría un enfoque más liviano para atravesar la cadena de respuesta completa sin tener que agregar una categoría en UIView:
fuente
Combinando varias respuestas ya dadas, también lo envío con mi implementación:
La categoría es parte de mi biblioteca estática habilitada para ARC que envío en cada aplicación que creo. Ha sido probado varias veces y no encontré ningún problema o fuga.
PD: No necesita usar una categoría como lo hice si la vista en cuestión es una subclase suya. En el último caso, simplemente coloque el método en su subclase y estará listo.
fuente
Aunque técnicamente esto se puede resolver como lo recomienda pgb , en mi humilde opinión, este es un defecto de diseño. La vista no debería necesitar ser consciente del controlador.
fuente
He modificado de respuesta, así que puede pasar cualquier punto de vista, botón, etiqueta, etc. conseguirlo de los padres
UIViewController
. Aquí está mi código.Editar versión de Swift 3
Edición 2: - Extensión rápida
fuente
No olvide que puede obtener acceso al controlador de vista raíz para la ventana de la que la vista es una subvista. A partir de ahí, si está utilizando, por ejemplo, un controlador de vista de navegación y desea insertar una nueva vista:
Sin embargo, primero deberá configurar correctamente la propiedad rootViewController de la ventana. Haga esto cuando cree el controlador por primera vez, por ejemplo, en el delegado de su aplicación:
fuente
[[self navigationController] view]
es la vista (principal) "principal" de la ventana, larootViewController
propiedad de la ventana debe configurarse paranavigationController
que controle la vista "principal" de inmediato.Si bien estas respuestas son técnicamente correctas, incluido Ushox, creo que la forma aprobada es implementar un nuevo protocolo o reutilizar uno existente. Un protocolo aísla al observador de lo observado, algo así como poner una ranura de correo entre ellos. En efecto, eso es lo que Gabriel hace a través de la invocación del método pushViewController; la vista "sabe" que es un protocolo apropiado pedir educadamente a su navigationController que empuje una vista, ya que viewController se ajusta al protocolo navigationController. Si bien puede crear su propio protocolo, simplemente usando el ejemplo de Gabriel y reutilizando el protocolo UINavigationController está bien.
fuente
Me topé con una situación en la que tengo un pequeño componente que quiero reutilizar, y agregué un código en una vista reutilizable (en realidad no es mucho más que un botón que abre un
PopoverController
).Si bien esto funciona bien en el iPad (el
UIPopoverController
presente en sí mismo, por lo tanto, no necesita hacer referencia a aUIViewController
), hacer que el mismo código funcione significa que de repente haga referenciapresentViewController
a suUIViewController
. Un poco inconsistente ¿verdad?Como se mencionó anteriormente, no es el mejor enfoque tener lógica en su UIView. Pero se sintió realmente inútil envolver las pocas líneas de código necesarias en un controlador separado.
De cualquier manera, aquí hay una solución rápida, que agrega una nueva propiedad a cualquier UIView:
fuente
No creo que sea "mala" idea averiguar quién es el controlador de la vista en algunos casos. Lo que podría ser una mala idea es guardar la referencia a este controlador, ya que podría cambiar al igual que cambian las supervistas. En mi caso, tengo un captador que atraviesa la cadena de respuesta.
//.h
//.metro
fuente
El bucle while más simple para encontrar viewController.
fuente
Swift 4
(más conciso que las otras respuestas)
Mi caso de uso para el que tenga que acceder a la vista primero
UIViewController
: Tengo un objeto que se envuelve alrededorAVPlayer
/AVPlayerViewController
y quiero dar un simpleshow(in view: UIView)
método que va a incrustarAVPlayerViewController
enview
. Para eso, necesito acceder aview
'sUIViewController
.fuente
Esto no responde la pregunta directamente, sino que supone una suposición sobre la intención de la pregunta.
Si tiene una vista y en esa vista necesita llamar a un método en otro objeto, como por ejemplo el controlador de vista, puede usar el NSNotificationCenter en su lugar.
Primero cree su cadena de notificación en un archivo de encabezado
En su opinión, llame a postNotificationName:
Luego, en su controlador de vista, agrega un observador. Hago esto en viewDidLoad
Ahora (también en el mismo controlador de vista) implemente su método copyString: como se muestra en el @selector anterior.
No digo que esta sea la forma correcta de hacer esto, simplemente parece más limpio que ejecutar la primera cadena de respuesta. Utilicé este código para implementar un UIMenuController en un UITableView y pasar el evento nuevamente al UIViewController para poder hacer algo con los datos.
fuente
Seguramente es una mala idea y un diseño incorrecto, pero estoy seguro de que todos podemos disfrutar de una solución Swift de la mejor respuesta propuesta por @Phil_M:
Si su intención es hacer cosas simples, como mostrar un diálogo modal o datos de seguimiento, eso no justifica el uso de un protocolo. Personalmente almaceno esta función en un objeto de utilidad, puede usarla desde cualquier cosa que implemente el protocolo UIResponder como:
Todo el crédito a @Phil_M
fuente
Tal vez llego tarde aquí. Pero en esta situación no me gusta la categoría (contaminación). Me encanta de esta manera:
fuente
Solución más rápida
fuente
sequence
bit). Entonces, si "rápido" significa "más funcional", entonces supongo que es más rápido.Versión actualizada para swift 4: Gracias por @Phil_M y @ paul-slm
fuente
Versión Swift 4
Ejemplo de uso
fuente
Dos soluciones a partir de Swift 5.2 :
return
palabra clave ahora 🤓Solución 1:
Solución 2:
fuente
A la respuesta de Phil:
En línea:
id nextResponder = [self nextResponder];
si self (UIView) no es una subvista de la vista ViewController, si conoce la jerarquía de self (UIView) puede usar también:id nextResponder = [[self superview] nextResponder];
...fuente
Mi solución probablemente se consideraría un poco falsa, pero tuve una situación similar a la de mayoneez (quería cambiar de vista en respuesta a un gesto en un EAGLView), y obtuve el controlador de vista del EAGL de esta manera:
fuente
EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
.ClassName *object
, con un asterisco.Creo que hay un caso en que lo observado necesita informar al observador.
Veo un problema similar en el que el UIView en un UIViewController está respondiendo a una situación y necesita primero decirle a su controlador de vista principal que oculte el botón Atrás y luego, al finalizar, decirle al controlador de vista principal que necesita salir de la pila.
He estado intentando esto con delegados sin éxito.
No entiendo por qué esto debería ser una mala idea?
fuente
Otra forma fácil es tener su propia clase de vista y agregar una propiedad del controlador de vista en la clase de vista. Por lo general, el controlador de vista crea la vista y ahí es donde el controlador puede establecerse en la propiedad. Básicamente, es en lugar de buscar (con un poco de pirateo) el controlador, tener el controlador configurado para la vista; esto es simple pero tiene sentido porque es el controlador el que "controla" la vista.
fuente
Si no va a subir esto a la App Store, también puede usar un método privado de UIView.
fuente
fuente
Para obtener el controlador de una vista dada, uno puede usar la cadena UIFirstResponder.
fuente
Si su rootViewController es UINavigationViewController, que se configuró en la clase AppDelegate, entonces
Donde c requiere ver la clase de controladores.
USO:
fuente
No hay manera
Lo que hago es pasar el puntero UIViewController a UIView (o una herencia apropiada). Lo siento, no puedo ayudar con el enfoque del problema de IB porque no creo en IB.
Para responder al primer comentarista: a veces necesita saber quién lo llamó porque determina lo que puede hacer. Por ejemplo, con una base de datos, es posible que solo tenga acceso de lectura o lectura / escritura ...
fuente