Digamos que tengo un guión gráfico que contiene UINavigationController
como controlador de vista inicial. Su controlador de vista raíz es una subclase de UITableViewController
, que es BasicViewController
. Tiene el IBAction
que está conectado al botón de navegación derecho de la barra de navegación.
Desde allí, me gustaría usar el guión gráfico como plantilla para otras vistas sin tener que crear guiones gráficos adicionales. Digamos que estas vistas tendrán exactamente la misma interfaz pero con el controlador de vista raíz de la clase SpecificViewController1
y SpecificViewController2
cuáles son subclases de BasicViewController
.
Esos 2 controladores de vista tendrían la misma funcionalidad e interfaz excepto por el IBAction
método.
Sería como lo siguiente:
@interface BasicViewController : UITableViewController
@interface SpecificViewController1 : BasicViewController
@interface SpecificViewController2 : BasicViewController
¿Puedo hacer algo así?
¿Puedo crear una instancia del guión gráfico de BasicViewController
pero tengo un controlador de vista raíz en una subclase SpecificViewController1
y SpecificViewController2
?
Gracias.
Respuestas:
gran pregunta, pero desafortunadamente solo una respuesta pobre. No creo que actualmente sea posible hacer lo que propone porque no hay inicializadores en UIStoryboard que permitan anular el controlador de vista asociado con el guión gráfico como se define en los detalles del objeto en el guión gráfico en la inicialización. Es en la inicialización que todos los elementos de la IU en el tablero de almacenamiento están vinculados a sus propiedades en el controlador de vista.
De forma predeterminada, se inicializará con el controlador de vista que se especifica en la definición del guión gráfico.
Si está tratando de obtener la reutilización de los elementos de la interfaz de usuario que creó en el guión gráfico, aún deben estar vinculados o asociados a propiedades en las que el controlador de vista los esté usando para que puedan "decirle" al controlador de vista sobre los eventos.
No es gran cosa copiar sobre el diseño de un guión gráfico, especialmente si solo necesita un diseño similar para 3 vistas, sin embargo, si lo hace, debe asegurarse de que todas las asociaciones anteriores estén borradas, o se bloqueará cuando lo intente para comunicarse con el controlador de vista anterior. Podrá reconocerlos como mensajes de error KVO en la salida del registro.
Un par de enfoques que podría tomar:
almacene los elementos de la interfaz de usuario en un UIView, en un archivo xib, cree una instancia de su clase base y agréguelo como una subvista en la vista principal, generalmente self.view. Luego, simplemente usaría el diseño del guión gráfico con controladores de vista básicamente en blanco que ocupan su lugar en el guión gráfico pero con la subclase de controlador de vista correcta asignada a ellos. Como heredarían de la base, obtendrían esa vista.
cree el diseño en código e instálelo desde su controlador de vista base. Obviamente, este enfoque frustra el propósito de usar el guión gráfico, pero puede ser el camino a seguir en su caso. Si tiene otras partes de la aplicación que se beneficiarían del enfoque del guión gráfico, está bien desviarse aquí y allá si corresponde. En este caso, como arriba, solo usaría controladores de vista de banco con su subclase asignada y dejaría que el controlador de vista base instale la interfaz de usuario.
Sería bueno que Apple encontrara una forma de hacer lo que propones, pero el problema de tener los elementos gráficos preenlazados con la subclase del controlador seguiría siendo un problema.
que tengas un gran año nuevo !! cuidate
fuente
El código de línea que buscamos es:
En Storyboard -> agregar UIViewController, asígnele un nombre de clase ParentVC.
fuente
class func instantiate() -> SubClass { let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)! object_setClass(instance, SubClass.self) return (instance as? SubClass)! }
self
no cambia. Por lo tanto, la inspección del objeto (por ejemplo, leer _ivar / valores de propiedad) despuésobject_setClass
puede causar bloqueos.Como dice la respuesta aceptada, no parece que sea posible hacerlo con guiones gráficos.
Mi solución es usar Nib's, al igual que los desarrolladores los usaban antes de los guiones gráficos. Si desea tener un controlador de vista subclase reutilizable (o incluso una vista), mi recomendación es usar Nibs.
Cuando conecta todas sus salidas al "Propietario del archivo" en el
MyViewController.xib
NO está especificando en qué clase se debe cargar el Nib, solo está especificando pares clave-valor: " esta vista debe estar conectada a este nombre de variable de instancia ". Al llamar[SubclassMyViewController alloc] initWithNibName:
al proceso de inicialización, se especifica qué controlador de vista se utilizará para " controlar " la vista que creó en la plumilla.fuente
Es posible hacer que un guión gráfico cree una instancia de diferentes subclases de un controlador de vista personalizado, aunque implica una técnica ligeramente poco ortodoxa: anular el
alloc
método para el controlador de vista. Cuando se crea el controlador de vista personalizado, el método alloc anulado de hecho devuelve el resultado de la ejecuciónalloc
en la subclase.Debo comenzar la respuesta con la condición de que, aunque lo probé en varios escenarios y no recibí errores, no puedo asegurar que se adapte a configuraciones más complejas (pero no veo ninguna razón por la que no debería funcionar) . Además, no he enviado ninguna aplicación con este método, por lo que existe la posibilidad de que sea rechazada por el proceso de revisión de Apple (aunque, nuevamente, no veo ninguna razón por la que debería hacerlo).
Para fines de demostración, tengo una subclase de
UIViewController
calledTestViewController
, que tiene un UILabel IBOutlet y un IBAction. En mi guión gráfico, agregué un controlador de vista y modifiqué su claseTestViewController
y conecté IBOutlet a un UILabel y IBAction a un UIButton. Presento el TestViewController mediante un segue modal desencadenado por un UIButton en el viewController anterior.Para controlar qué clase se instancia, he agregado una variable estática y métodos de clase asociados, así que obtenga / configure la subclase que se utilizará (supongo que se podrían adoptar otras formas de determinar qué subclase se instanciará):
TestViewController.m:
Para mi prueba tengo dos subclases de
TestViewController
:RedTestViewController
yGreenTestViewController
. Cada una de las subclases tiene propiedades adicionales y cada una se reemplazaviewDidLoad
para cambiar el color de fondo de la vista y actualizar el texto de UILabel IBOutlet:RedTestViewController.m:
GreenTestViewController.m:
En algunas ocasiones podría querer crear
TestViewController
una instancia de sí mismo, en otras ocasionesRedTestViewController
oGreenTestViewController
. En el controlador de vista anterior, hago esto al azar de la siguiente manera:Tenga en cuenta que el
setClassForStoryBoard
método verifica para asegurarse de que el nombre de clase solicitado sea de hecho una subclase de TestViewController, para evitar confusiones. La referencia anterior aBlueTestViewController
está ahí para probar esta funcionalidad.fuente
intente esto, después de instantiateViewControllerWithIdentifier.
me gusta :
fuente
EXC_BAD_ACCESS
, así que no recomiendo esto.init
tampoco se llamará. Tales limitaciones hacen que todo enfoque sea inutilizable.Basándome particularmente en las respuestas de nickgzzjr y Jiří Zahálka más el comentario debajo del segundo de CocoaBob, he preparado un método genérico corto que hace exactamente lo que OP necesita. Solo necesita verificar el nombre del guión gráfico y el ID del guión gráfico de View Controllers
Se agregan opcionales para evitar el desenvolvimiento forzado (advertencias de swiftlint), pero el método devuelve los objetos correctos.
fuente
Aunque no es estrictamente una subclase, puede:
Aquí hay un ejemplo de un tutorial de Bloc que escribí, subclasificado
ViewController
conWhiskeyViewController
:Esto le permite crear subclases de subclases de controlador de vista en el guión gráfico. A continuación, puede utilizar
instantiateViewControllerWithIdentifier:
para crear subclases específicas.Este enfoque es un poco inflexible: las modificaciones posteriores dentro del guión gráfico al controlador de clase base no se propagan a la subclase. Si tiene muchas subclases, puede estar mejor con una de las otras soluciones, pero esto funcionará en un apuro.
fuente
initWithCoder:
, no tienen una relación heredada. Este tipo de relación no es compatible con archivos de guiones gráficos.El método Objc_setclass no crea una instancia de childvc. Pero mientras sale de childvc, se llama a deinit of childvc. Dado que no hay memoria asignada por separado para childvc, la aplicación se bloquea. Basecontroller tiene una instancia, mientras que child vc no tiene.
fuente
Si no depende demasiado de los guiones gráficos, puede crear un archivo .xib separado para el controlador.
Establezca el propietario y las salidas del archivo apropiado en
MainViewController
y anuleinit(nibName:bundle:)
en el VC principal para que sus hijos puedan acceder al mismo Nib y sus salidas.Tu código debería verse así:
Y su Child VC podrá reutilizar la punta de su padre:
fuente
Tomando respuestas de aquí y de allá, se me ocurrió esta excelente solución.
Cree un controlador de vista principal con esta función.
Esto permite al compilador asegurarse de que el controlador de vista secundario hereda del controlador de vista principal.
Luego, siempre que quiera pasar a este controlador usando una subclase, puede hacer:
Lo bueno es que puede agregar una referencia de guión gráfico a sí mismo y luego seguir llamando al controlador de vista secundario "siguiente".
fuente
Probablemente, la forma más flexible es utilizar vistas reutilizables.
(Cree una vista en un archivo XIB separado o
Container view
agréguela a cada escena del controlador de vista de subclase en el guión gráfico)fuente
Existe una solución simple, obvia y cotidiana.
Simplemente coloque el storyboard / controlador existente dentro del nuevo storyobard / controller. IE como vista de contenedor.
Este es el concepto exactamente análogo a "subclasificar", para controladores de vista.
Todo funciona exactamente como en una subclase.
Así como normalmente coloca una subvista de vista dentro de otra vista , naturalmente coloca un controlador de vista dentro de otro controlador de vista .
¿De qué otra manera podrías hacerlo?
Es una parte básica de iOS, tan simple como el concepto de "subvista".
Es así de fácil ...
Ahora obviamente tienes
list
que hacer lo que quieras conetcétera etcétera.
Las vistas de contenedor son "como" subclases de la misma forma que las "subvistas" son "como" subclases.
Por supuesto, obviamente, no se puede "subcasar un diseño", ¿qué significa eso?
("Subclasificación" se relaciona con el software OO y no tiene conexión con los "diseños").
Obviamente, cuando desee reutilizar una vista, simplemente la subvista dentro de otra vista.
Cuando desee reutilizar un diseño de controlador, simplemente lo ve dentro de otro controlador.
¡Este es el mecanismo más básico de iOS!
Nota: durante años ha sido trivial cargar dinámicamente otro controlador de vista como una vista de contenedor. Explicado en la última sección: https://stackoverflow.com/a/23403979/294884
Nota: "_sb" es solo una macro obvia que usamos para guardar la escritura,
fuente
Gracias por la inspiradora respuesta de @ Jiří Zahálka, respondí mi solución hace 4 años aquí , pero @Sayka me sugirió publicarla como respuesta, así que aquí está.
En mis proyectos, normalmente, si estoy usando Storyboard para una subclase UIViewController, siempre preparo un método estático llamado
instantiate()
en esa subclase, para crear una instancia de Storyboard fácilmente. Entonces, para resolver la pregunta de OP, si queremos compartir el mismo Storyboard para diferentes subclases, podemos simplementesetClass()
ir a esa instancia antes de devolverla.fuente
El comentario de Cocoabob de la respuesta de Jiří Zahálka me ayudó a obtener esta solución y funcionó bien.
fuente