以编程方式设置 UIViewController 的视图和生命周期
Programmatically setting an UIViewController's view and life cycle
我的应用程序中有几个针对 iOS 7+ 的视图显示 MKMapView
。我想要一个 UIViewController
来管理那些 MKMapView
视图,所以我尝试创建一个 UIViewController
subclass 符合 MKMapViewDelegate
协议:
@interface MapViewController : UIViewController <MKMapViewDelegate>
此 MapViewController
class 没有关联的 nib
文件。然后,在管理视图的视图控制器中,我想在其中显示 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];
这样,我可以看到 MapViewController
中的 viewWillAppear:
方法被调用,但 viewDidLoad:
方法没有被调用。
这是做我想做的事情的正确方法吗?为什么 viewDidLoad:
没有被调用?
提前致谢
这里有两个问题:
- 您不应该设置
UIViewController
的 view
属性。事实上,您应该将 UIViewController
的视图层次视为私有。
- 您应该使用 Apple 的
UIViewController
容器 API 以确保正确调用 viewWillAppear:
等
所以这是你应该做的:
必须在 MapViewController
的 -loadView
中创建 MKMapView
:
- (void)loadView
{
MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
map.delegate = self;
self.view = map;
}
当您将子 ViewController 添加到视图层次结构时,您应该这样做:
self.mapController = [[MapViewController alloc] init];
[self addChildViewController:self.mapController];
[self.view addSubview:self.mapController.view];
[self.mapController didMoveToParentViewController:self];
当您出于任何原因从视图层次结构中删除子项 ViewController 时,您应该这样做:
[self.mapController willMoveToParentViewController:nil];
[self.mapController.view removeFromSuperview];
[self.mapController removeFromParentViewController];
有关容器视图控制器的更多详细信息,请参阅
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
视图控制器如何加载它的视图?
Apple 的观点 属性 getter 实现看起来很像这样:
- (UIView *)view
{
[self loadViewIfNeeded];
return _view;
}
- (void)loadViewIfNeeded
{
if (_view == nil) {
[self loadView];
[self viewDidLoad];
}
}
当您访问视图控制器的 view
属性 时,它会检查 view
是否实际上为 nil。如果它是 nil,它会在返回 view
.
之前调用 -loadView
,然后调用 -viewDidLoad
因此,当您在第一次访问之前设置视图 属性 时,-loadView
和 -viewDidLoad
将永远不会被调用。
我的应用程序中有几个针对 iOS 7+ 的视图显示 MKMapView
。我想要一个 UIViewController
来管理那些 MKMapView
视图,所以我尝试创建一个 UIViewController
subclass 符合 MKMapViewDelegate
协议:
@interface MapViewController : UIViewController <MKMapViewDelegate>
此 MapViewController
class 没有关联的 nib
文件。然后,在管理视图的视图控制器中,我想在其中显示 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];
这样,我可以看到 MapViewController
中的 viewWillAppear:
方法被调用,但 viewDidLoad:
方法没有被调用。
这是做我想做的事情的正确方法吗?为什么 viewDidLoad:
没有被调用?
提前致谢
这里有两个问题:
- 您不应该设置
UIViewController
的view
属性。事实上,您应该将UIViewController
的视图层次视为私有。 - 您应该使用 Apple 的
UIViewController
容器 API 以确保正确调用viewWillAppear:
等
所以这是你应该做的:
必须在 MapViewController
的 -loadView
中创建 MKMapView
:
- (void)loadView
{
MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
map.delegate = self;
self.view = map;
}
当您将子 ViewController 添加到视图层次结构时,您应该这样做:
self.mapController = [[MapViewController alloc] init];
[self addChildViewController:self.mapController];
[self.view addSubview:self.mapController.view];
[self.mapController didMoveToParentViewController:self];
当您出于任何原因从视图层次结构中删除子项 ViewController 时,您应该这样做:
[self.mapController willMoveToParentViewController:nil];
[self.mapController.view removeFromSuperview];
[self.mapController removeFromParentViewController];
有关容器视图控制器的更多详细信息,请参阅 https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
视图控制器如何加载它的视图?
Apple 的观点 属性 getter 实现看起来很像这样:
- (UIView *)view
{
[self loadViewIfNeeded];
return _view;
}
- (void)loadViewIfNeeded
{
if (_view == nil) {
[self loadView];
[self viewDidLoad];
}
}
当您访问视图控制器的 view
属性 时,它会检查 view
是否实际上为 nil。如果它是 nil,它会在返回 view
.
-loadView
,然后调用 -viewDidLoad
因此,当您在第一次访问之前设置视图 属性 时,-loadView
和 -viewDidLoad
将永远不会被调用。