【问题标题】:Programmatically setting an UIViewController's view and life cycle以编程方式设置 UIViewController 的视图和生命周期
【发布时间】:2015-01-13 14:20:24
【问题描述】:

我的应用中有几个针对 iOS 7+ 的视图,显示 MKMapView。我想要一个UIViewController 来管理那些MKMapView 视图,所以我尝试创建一个符合MKMapViewDelegate 协议的UIViewController 子类:

@interface MapViewController : UIViewController <MKMapViewDelegate>

此MapViewController 类没有关联的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:?

提前致谢

【问题讨论】:

  • 为什么不直接将MKMapView 添加到您的视图中?

标签: ios uiview uiviewcontroller mkmapview xib


【解决方案1】:

这里有两个问题:

  • 不应设置UIViewController 的view 属性。实际上,您应该将 UIViewController 的视图层次结构视为私有的。
  • 您应该使用 Apple 的 UIViewController 包含 API 以确保正确调用 viewWillAppear: 等。

所以你应该这样做:

MKMapView 必须在-loadView 的MapViewController 中创建:

- (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,则调用 -loadView,然后调用 -viewDidLoad,然后返回 view。

因此,当您在第一次访问视图属性之前设置它,-loadView 和 -viewDidLoad 将永远不会被调用。

【讨论】:

    猜你喜欢
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多