I have several views in my app targeted for iOS 7+ that show a MKMapView
. I'd like to have a single UIViewController
to manage those MKMapView
views, so I tried to create an UIViewController
subclass conforming MKMapViewDelegate
protocol:
@interface MapViewController : UIViewController <MKMapViewDelegate>
This MapViewController
class has not an associated nib
file. Then, in the view controller that manages the view where I want to show a MKMapView
:
self.mapController = [[MapViewController alloc] init];
MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
map.delegate = self.mapController;
[self.mapController setView:map];
[self.view addSubview:self.mapController.view];
This way, I can see that viewWillAppear:
method in MapViewController
is called, but viewDidLoad:
method isn't.
Is this the correct way to do what I want? Why is viewDidLoad:
not called?
Thanks in advance
There are two problems here:
view
property of a UIViewController
. In fact, you should consider the view hierarchy of a UIViewController
as private.UIViewController
containment API to ensure proper invocation of viewWillAppear:
etc.So here's what you should do:
The MKMapView
must be created in -loadView
of MapViewController
:
- (void)loadView
{
MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
map.delegate = self;
self.view = map;
}
When you add the child ViewController to the view hierarchy you should do this:
self.mapController = [[MapViewController alloc] init];
[self addChildViewController:self.mapController];
[self.view addSubview:self.mapController.view];
[self.mapController didMoveToParentViewController:self];
when you remove the child ViewController from the view hierarchy for whatever reason you should do this:
[self.mapController willMoveToParentViewController:nil];
[self.mapController.view removeFromSuperview];
[self.mapController removeFromParentViewController];
For more details about container view controllers please refer to https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
How does a view controller load its view?
Apple's view property getter implementation looks a lot like this:
- (UIView *)view
{
[self loadViewIfNeeded];
return _view;
}
- (void)loadViewIfNeeded
{
if (_view == nil) {
[self loadView];
[self viewDidLoad];
}
}
when you access the view
property of a view controller, it checks if view
is actually nil. If it is nil, it invokes -loadView
and then -viewDidLoad
before returning view
.
Therefore when you set the view property before accessing it the first time, -loadView
and -viewDidLoad
will never be invoked.