ios - life - Swift: Subclasificando la vista raíz de un UIViewController
uiviewcontroller lifecycle (3)
tl; dr: ¿Cómo puedo decirle a Swift que estoy anulando la propiedad de view
de UIView
con una subclase de UIView
?
Que me gustaria hacer
Soy un gran fan de proporcionar una subclase de UIView
para una vista de UIViewController
. Por ejemplo:
// MyView --------------------------------------------------------
@interface MyView: UIView
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation MyView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
_tableView = [[UITableView alloc] initWithFrame:frame];
}
return self;
}
@end
// MyViewController ----------------------------------------------
@interface MyViewController: UIViewController <UITableViewDataSource>
@property (nonatomic, retain) MyView *view;
@end
@implementation MyViewController
- (void)loadView {
self.view = [[MyView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.tableView.dataSource = self;
// etc.
}
@end
Esto es excelente porque separa la creación de vista y la lógica de diseño del controlador de vista. Está bien.
Tan cerca como puedo imaginar, esto se traduce en Swift así:
// MyView --------------------------------------------------------
class MyView: UIView {
let tableView: UITableView!
init(frame: CGRect) {
super.init(frame: frame)
tableView = UITableView(frame: frame)
}
}
// MyViewController ----------------------------------------------
class MyViewController: UIViewController, UITableViewDataSource {
override func loadView() {
view = MyView(frame: UIScreen.mainScreen().bounds)
}
override func viewDidLoad() {
super.viewDidLoad()
// this causes the compiler to complain with:
// ''UIView'' does not have a member named ''tableView''
self.view.tableView.dataSource = self
}
}
El problema es que parece que no puedo entender cómo decirle al controlador de vista que su view
es una instancia de MyView
lugar de UIView
.
Intentos fallidos
Esto es lo que he intentado hasta ahora:
He intentado esto en la parte superior de MyViewController
, con el siguiente error:
override var view: MyView!
// error: Cannot override mutable property ''view'' of
// type ''UIView'' with covariant type ''MyView!''
He intentado esto en loadView
, pero no loadView
suerte:
view = MyView(frame: UIScreen.mainScreen().bounds) as MyView
// this produces the same error as in the original code:
// ''UIView'' does not have a member named ''tableView''
Así que aquí está la pregunta
¿Cómo puedo decirle a Swift que estoy anulando la propiedad de view
de MyView
con una de la subclase MyView
? ¿Es esto posible? ¿Si no, porque no?
¿Podemos usar algo como esto?
class MyViewController: UIViewController, UIScrollViewDelegate {
weak var viewAlias: UIScrollView!
override func loadView() {
let scrollView = UIScrollView(frame: UIScreen.mainScreen().bounds)
viewAlias = scrollView
view = scrollView
}
override func viewDidLoad() {
//super.viewDidLoad()
viewAlias.delegate = self
viewAlias.contentSize = view.frame.size
// Do any additional setup after loading the view.
}
Creo que la misma implementación exacta puede no ser posible en Swift. De la sección del libro Swift sobre las propiedades de anulación:
"Siempre debe indicar tanto el nombre como el tipo de propiedad que está anulando, para que el compilador pueda verificar que su anulación coincida con una propiedad de superclase con el mismo nombre y tipo".
Sin embargo, podría usar una propiedad computada que devuelva una versión encasillada de la propiedad de view
de su controlador de view
, y sería casi tan limpia:
class MyViewController: UIViewController, UITableViewDataSource {
var myView: MyView! { return self.view as MyView }
override func loadView() {
view = MyView(frame: UIScreen.mainScreen().bounds)
}
override func viewDidLoad() {
super.viewDidLoad()
self.myView.tableView.dataSource = self
}
}
[Desarrollador de Apple] lo hace de esta manera 1 :
A continuación se muestra cómo puede anular el método viewDidLoad () de un controlador de vista para convertir su vista en un SKView:
override func viewDidLoad() { super.viewDidLoad() view = SKView() } var skView: SKView { return view as! SKView }
Alternativamente, la nueva plantilla de juego del proyecto de Xcode lo hace de esta manera:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Can now set up view as if it were a SKView.
}
}