medium - swift protocol and delegate example
¿Cómo declaro una variable que tiene un tipo e implementa un protocolo? (3)
A partir de Swift 4, ahora puede hacer esto.
Swift 4 implementó SE-0156 (Clase y Subtipo existencial).
El equivalente de esta sintaxis de Objective-C:
@property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Ahora se ve así en Swift 4:
var detailViewController: UIViewController & DetailViewController
Esencialmente se llega a definir una clase a la que se ajusta la variable, y N número de protocolos que implementa. Consulte el documento vinculado para obtener información más detallada.
Mi aplicación tiene un protocolo para los controladores de vista detallada, indicando que deben tener una propiedad viewModel
:
protocol DetailViewController: class {
var viewModel: ViewModel? {get set}
}
También tengo algunas clases diferentes que implementan el protocolo:
class FormViewController: UITableViewController, DetailViewController {
// ...
}
class MapViewController: UIViewController, DetailViewController {
// ...
}
Mi controlador de vista maestro necesita una propiedad que se puede establecer en cualquier subclase UIViewController
que implemente el protocolo DetailViewController
.
Desafortunadamente no puedo encontrar ninguna documentación sobre cómo hacer esto. En Objective-C sería trivial:
@property (strong, nonatomic) UIViewController<DetailViewController>;
Parece que no hay ninguna sintaxis disponible en Swift para hacer esto. Lo más cerca que he llegado es declarar un genérico en mi definición de clase:
class MasterViewController<T where T:UIViewController, T:DetailViewController>: UITableViewController {
var detailViewController: T?
// ...
}
Pero luego aparece un error que dice que "Class ''MasterViewController'' no implementa los miembros requeridos de su superclase"
Parece que debería ser tan fácil de hacer en Swift como en Objective-C, pero no puedo encontrar nada en ninguna parte que sugiera cómo podría hacerlo.
Creo que puede obtenerlo agregando una extensión (vacía) a UIViewController
y luego especificando su atributo detailViewController
utilizando un protocolo compuesto de la extensión vacía y su DetailViewController
. Me gusta esto:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
Ahora todas las subclases de UIViewController
satisfacen el protocolo UIViewControllerInject
. Luego con eso, simplemente:
typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>
class MasterViewController : UITableViewController {
var detailViewController : DetailViewControllerComposed?
// ...
}
Pero, esto no es particularmente ''natural''.
=== Editar, Adición ===
En realidad, podrías mejorar un poco si defines tu DetailViewController
usando mi UIViewControllerInject
sugerido. Como tal:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
protocol DetailViewController : UIViewControllerInject { /* ... */ }
y ahora no necesita componer explícitamente algo (mi DetailViewControllerComposed
) y puede usar DetailViewController?
como el tipo para detailViewController
.
Otra forma sería introducir clases base intermedias para los controladores de vista UIKit apropiados que implementan el protocolo:
class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...
Luego, hereda sus controladores de vista de estos controladores de vista, no los de UIKit.
Esto tampoco es natural, pero no obliga a todos sus UIViewControllers
a satisfacer el protocolo UIViewControllerInject como lo sugirió GoZoner.