Reputation: 11287
tl;dr: How can I tell Swift that I'm overriding MyViewController
's view
property with a subclass of UIView
?
I'm a big fan of providing a subclass of UIView
for a UIViewController
's view. For example:
// 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
This is great because it separates the view creation and layout logic from the view controller. Ok, fine.
Near as I can figure, this translates into Swift like so:
// 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
}
}
The trouble is I can't seem to figure out how to tell the view controller that its view
is an instance of MyView
rather than UIView
itself.
Here's what I've tried so far:
I've tried this at the top of MyViewController
, with the following error:
override var view: MyView!
// error: Cannot override mutable property 'view' of
// type 'UIView' with covariant type 'MyView!'
I've tried this in loadView
, but no luck:
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'
How can I tell Swift that I'm overriding MyViewController
's view
property with one of subclass MyView
? Is this even possible? If not, why not?
Upvotes: 23
Views: 17319
Reputation: 253
can we use something like this?
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.
}
Upvotes: 0
Reputation: 93276
I think the exact same implementation may not be possible in Swift. From the Swift book section about overriding properties:
“You must always state both the name and the type of the property you are overriding, to enable the compiler to check that your override matches a superclass property with the same name and type.”
However, you could use a computed property that returns a typecast version of your view controller's view
property, and it would be almost as clean:
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
}
}
Upvotes: 26