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?
final class MyViewController: UIViewController { let myView = MyView() override func viewDidLoad() { super. viewDidLoad() setupMyView() } private func setupMyView() { view. addSubview(myView) //10 lines of constraints or so myView. delegate = self //We now have both 'view' and 'myView'... } }
ContentView -> View1 -> View2And from View2 you want to pop to the Root view.
The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.
View controllers act as a data source or delegate for another object. View controllers are often used to manage the data for tables, and collection views. You can also use them as a delegate for an object such as a CLLocationManager object, which sends updated location values to its delegate.
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With