Básicamente, estoy tratando de llamar mi vista La vista del Controlador Aparecerá mientras mi vista se descarta. La vista está siendo descartada por la vista misma que está detectando un toque y llamando [self removeFromSuperview]; ViewController no está llamando a viewWillAppear / WillDisappear / DidAppear / DidDisappear.
mahboudz
Quise decir que estoy tratando de llamar a viewWillDisappear ya que mi vista se está descartando.
Sí, superviewes la vista que contiene su vista. Su vista no debería saber cuál es exactamente su controlador de vista, porque eso rompería los principios de MVC.
El controlador, por otro lado, sabe de qué vista es responsable ( self.view = myView), y generalmente, esta vista delega métodos / eventos para su manejo al controlador.
Por lo general, en lugar de un puntero a su vista, debe tener un puntero a su controlador, que a su vez puede ejecutar alguna lógica de control o pasar algo a su vista.
No estoy seguro de si rompería los principios de MVC. En cualquier punto, una vista solo tiene un controlador de vista. Poder acceder a él para devolverle un mensaje debe ser una función automática, no una en la que tenga que trabajar para lograrlo (agregando una propiedad para realizar un seguimiento). Se podría decir lo mismo sobre las opiniones: ¿por qué necesita saber quién es su hijo? O si hay otras vistas de hermanos. Sin embargo, hay formas de obtener esos objetos.
mahboudz
Tiene algo de razón acerca de la vista, ya que conoce su elemento primario, no es una decisión de diseño súper clara, pero ya está establecido para realizar algunas acciones, utilizando directamente una variable de miembro de la supervista (verificar el tipo principal, eliminar del elemento primario, etc.). Después de haber trabajado con PureMVC recientemente, me he vuelto un poco más quisquilloso con la abstracción del diseño :) Haría un paralelo entre las clases UIView y UIViewController de iPhone y las clases View y Mediator de PureMVC; la mayoría de las veces, la clase View no necesita Conozca su manejador / interfaz MVC (UIViewController / Mediator).
Dimitar Dimitrov
9
Palabra clave: "la mayoría".
Glenn Maynard
278
De la UIResponderdocumentación para nextResponder:
La clase UIResponder no almacena ni establece el siguiente respondedor automáticamente, sino que devuelve nil por defecto. Las subclases deben anular este método para establecer el próximo respondedor. UIView implementa este método devolviendo el objeto UIViewController que lo administra (si tiene uno) o su supervista (si no lo tiene) ; UIViewController implementa el método devolviendo la vista general de su vista; UIWindow devuelve el objeto de la aplicación y UIApplication devuelve nil.
Por lo tanto, si repite una vista nextResponderhasta que sea de tipo UIViewController, entonces tiene el control de vista principal de cualquier vista.
Tenga en cuenta que aún puede no tener un controlador de vista principal. Pero solo si la vista no forma parte de la jerarquía de vistas de una vista del Controlador.
Solo una cosa: si le preocupa la contaminación por categorías, simplemente defínalo como una función estática en lugar de una macro. Además, el brutal tipo de letra es peligroso y, además, la macro puede no ser correcta, pero no estoy seguro.
mojuba
La macro funciona, solo uso la versión macro personalmente. Comienzo una gran cantidad de proyectos y tengo un encabezado que acabo de colocar en todas partes con un montón de estas funciones de macro utilidad. Me ahorra tiempo. Si no le gustan las macros, puede adaptarlas a una función, pero las funciones estáticas parecen tediosas, ya que debe colocar una en cada archivo que desee usar. ¿Parece que en su lugar desearía una función no estática declarada en un encabezado y definida en un .m en algún lugar?
mxcl
Es bueno evitar algunos delegados o notificaciones. ¡Gracias!
Ferran Maylinch 01 de
Debería convertirlo en una extensión de UIResponder;). Puesto muy edificante.
ScottyBlades
32
@andrey responde en una línea (probado en Swift 4.1 ):
parentViewControllerno se puede definir publicsi la extensión está en el mismo archivo con el UIViewque puede configurarla fileprivate, se compila pero no funciona. 😐
Esta funcionando bien He usado esto para la acción del botón de retroceso dentro del archivo .xib de encabezado común.
McDonal_11
23
Solo para fines de depuración, puede llamar _viewDelegatea las vistas para obtener sus controladores de vista. Esta es una API privada, por lo que no es segura para App Store, pero es útil para la depuración.
Otros métodos útiles:
_viewControllerForAncestor- Obtenga el primer controlador que gestiona una vista en la cadena de supervista. (gracias n00neimp0rtant)
_rootAncestorViewController - Obtener el controlador ancestro cuya jerarquía de vista está configurada en la ventana actualmente.
Esto es exactamente por qué llegué a esta pregunta. Aparentemente, 'nextResponder' hace lo mismo, pero agradezco la información que proporciona esta respuesta. Entiendo y me gusta MVC, ¡pero la depuración es un animal diferente!
mbm29414
44
Parece que esto solo funciona en la vista principal del controlador de vista, no en ninguna subvista de la misma. _viewControllerForAncestorrecorrerá las supervistas hasta que encuentre la primera que pertenezca a un controlador de vista.
n00neimp0rtant
Gracias @ n00neimp0rtant! Estoy votando esta respuesta para que la gente vea tu comentario.
eyuelt
Actualiza la respuesta con más métodos.
Leo Natan
1
Esto es útil al depurar.
evanchin
10
Para obtener referencia a que UIViewController tiene UIView, puede hacer una extensión de UIResponder (que es una superclase para UIView y UIViewController), que permite subir a través de la cadena de respuesta y así llegar a UIViewController (de lo contrario, devuelve nulo).
Creo que puede propagar el grifo al controlador de vista y dejar que lo maneje. Este es un enfoque más aceptable. En cuanto a acceder a un controlador de vista desde su vista, debe mantener una referencia a un controlador de vista, ya que no hay otra manera. Vea este hilo, podría ayudar:
Acceder al controlador de vista desde una vista
Si tiene un puñado de vistas, y una cierra todas las vistas, y necesita llamar a viewWillDisappear, ¿no sería más fácil para esa vista detectar el grifo que pasar el grifo al controlador de vista y hacer que el controlador de vista verifique con todas las vistas para ver cuál fue tocado?
Por desgracia, esto es imposible a menos que subclasifique la vista y le proporcione una propiedad de instancia o similar que almacene la referencia del controlador de vista dentro de ella una vez que la vista se agregue a la escena ...
En la mayoría de los casos, es muy fácil solucionar el problema original de esta publicación, ya que la mayoría de los controladores de vista son entidades conocidas para el programador que fue responsable de agregar subvistas a la Vista de ViewController ;-) Por eso supongo que Apple nunca se molestó en agregar esa propiedad.
Respuestas:
Sí,
superview
es la vista que contiene su vista. Su vista no debería saber cuál es exactamente su controlador de vista, porque eso rompería los principios de MVC.El controlador, por otro lado, sabe de qué vista es responsable (
self.view = myView
), y generalmente, esta vista delega métodos / eventos para su manejo al controlador.Por lo general, en lugar de un puntero a su vista, debe tener un puntero a su controlador, que a su vez puede ejecutar alguna lógica de control o pasar algo a su vista.
fuente
De la
UIResponder
documentación paranextResponder
:Por lo tanto, si repite una vista
nextResponder
hasta que sea de tipoUIViewController
, entonces tiene el control de vista principal de cualquier vista.Tenga en cuenta que aún puede no tener un controlador de vista principal. Pero solo si la vista no forma parte de la jerarquía de vistas de una vista del Controlador.
Extensión Swift 3 y Swift 4.1 :
Extensión Swift 2:
Categoría objetivo-C:
Esta macro evita la categoría de contaminación:
fuente
UIResponder
;). Puesto muy edificante.@andrey responde en una línea (probado en Swift 4.1 ):
uso:
fuente
parentViewController
no se puede definirpublic
si la extensión está en el mismo archivo con elUIView
que puede configurarlafileprivate
, se compila pero no funciona. 😐Solo para fines de depuración, puede llamar
_viewDelegate
a las vistas para obtener sus controladores de vista. Esta es una API privada, por lo que no es segura para App Store, pero es útil para la depuración.Otros métodos útiles:
_viewControllerForAncestor
- Obtenga el primer controlador que gestiona una vista en la cadena de supervista. (gracias n00neimp0rtant)_rootAncestorViewController
- Obtener el controlador ancestro cuya jerarquía de vista está configurada en la ventana actualmente.fuente
_viewControllerForAncestor
recorrerá las supervistas hasta que encuentre la primera que pertenezca a un controlador de vista.Para obtener referencia a que UIViewController tiene UIView, puede hacer una extensión de UIResponder (que es una superclase para UIView y UIViewController), que permite subir a través de la cadena de respuesta y así llegar a UIViewController (de lo contrario, devuelve nulo).
fuente
La forma rápida y genérica en Swift 3:
fuente
Si no está familiarizado con el código y desea encontrar ViewController correspondiente a la vista dada, puede intentar:
En la mayoría de los casos obtendrá UIView, pero de vez en cuando habrá una clase basada en UIViewController.
fuente
Creo que puede propagar el grifo al controlador de vista y dejar que lo maneje. Este es un enfoque más aceptable. En cuanto a acceder a un controlador de vista desde su vista, debe mantener una referencia a un controlador de vista, ya que no hay otra manera. Vea este hilo, podría ayudar: Acceder al controlador de vista desde una vista
fuente
Más código de tipo seguro para Swift 3.0
fuente
Por desgracia, esto es imposible a menos que subclasifique la vista y le proporcione una propiedad de instancia o similar que almacene la referencia del controlador de vista dentro de ella una vez que la vista se agregue a la escena ...
En la mayoría de los casos, es muy fácil solucionar el problema original de esta publicación, ya que la mayoría de los controladores de vista son entidades conocidas para el programador que fue responsable de agregar subvistas a la Vista de ViewController ;-) Por eso supongo que Apple nunca se molestó en agregar esa propiedad.
fuente
Un poco tarde, pero aquí hay una extensión que le permite encontrar un respondedor de cualquier tipo, incluido ViewController.
fuente
Si establece un punto de interrupción, puede pegarlo en el depurador para imprimir la jerarquía de vistas:
Debería poder encontrar el padre de su vista en algún lugar de ese desastre :)
fuente
recursiveDescription
solo imprime la jerarquía de vistas , no los controladores de vista.