Swift: подклассификация корневого представления UIViewController
tl; dr: Как я могу сказать Swift, что я переопределяю свойство MyViewController
view
с подклассом UIView
?
Что я хотел бы сделать
Я большой поклонник предоставления подкласса UIView
для представления UIViewController
. Например:
// 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
Это здорово, потому что он отделяет логику создания и компоновки представления от контроллера вида. Хорошо, отлично.
Вблизи, как я могу понять, это переводится как Swift так:
// 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
}
}
Проблема в том, что я не могу понять, как сообщить контроллеру представления, что его view
является экземпляром MyView
, а не UIView
.
Неудачные попытки
Вот что я пробовал до сих пор:
Я пробовал это в верхней части MyViewController
со следующей ошибкой:
override var view: MyView!
// error: Cannot override mutable property 'view' of
// type 'UIView' with covariant type 'MyView!'
Я пробовал это в loadView
, но не повезло:
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'
Итак, вопрос
Как я могу сказать Swift, что я переопределяю свойство MyViewController
view
с одним из подклассов MyView
? Возможно ли это? Если нет, почему бы и нет?
Ответы
Ответ 1
Я думаю, что точно такая же реализация может быть невозможна в Swift. Из раздела книги Swift о переопределении свойств:
"Вы должны всегда указывать как имя, так и тип свойства, которое вы являются переопределяющими, чтобы позволить компилятору проверить, что ваше переопределение соответствует свойству суперкласса с тем же именем и типом."
Однако вы можете использовать вычисленное свойство, которое возвращает тип версии вашего свойства управления представлением view
, и оно будет почти таким же чистым:
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
}
}
Ответ 2
можем ли мы использовать что-то вроде этого?
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.
}
Ответ 3
[Разработчик Apple] делает это так 1:
Ниже показано, как вы можете переопределить контроллеры представлений viewDidLoad(), чтобы отобразить его представление в SKView:
override func viewDidLoad() {
super.viewDidLoad()
view = SKView()
}
var skView: SKView {
return view as! SKView
}
В качестве альтернативы Xcode новый шаблон игры проекта делает это следующим образом:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Can now set up view as if it were a SKView.
}
}