正确的loadView实现

时间:2012-03-21 11:41:32

标签: ios uiview uiviewcontroller

Apple的文档没有说明loadView的正确实现是什么。

我发现如果你像这样实现loadView:

- (void)loadView
{
    self.view = [[UIView alloc] init];
}

...然后你得到的行为与你根本没有实现它的行为不同。特别是,在一个20行项目中,我发现viewWillAppear被调用为self.view的零大小框架 - 除非你使用Apple的默认版本的loadView。

在谷歌上看,有很多“教程”提供了明显错误的loadView实现 - 例如强制将大小设置为(320,480),因为教程作者“发现它可以正常工作”。

我想知道正确的实现应该是什么。

注意:在上面的例子中,我将它添加到AppDelegate中的视图层次结构中,如下所示:

[self.window addSubview:(UIViewController*).view];

我相信在存在UINavigationController或UITabBarController的情况下,Apple会做一些额外的魔术 - 作为副作用 - 导致单行loadView实现正常工作。但是我想正确地写它,以便总是有效!

注意:我已尝试在根视图上设置自动调整掩码,但它不会改变发生的情况:

- (void)loadView
{
    self.view = [[UIView alloc] init];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

2 个答案:

答案 0 :(得分:15)

-loadView 的默认实施会创建视图或加载NIB 。据我所知,-loadView无法知道创建时视图的最终大小。因此,默认视图大小设置为UIScreen.mainScreen.bounds。这是因为在-viewDidLoad和其他方法中使用零帧视图可能很困难。

您的单行实施可能如下所示:

- (void)loadView {
    self.view = [[UIView alloc] initWithFrame:UIScreen.mainScreen.bounds];
}

您无需设置自动调整大小,因为您不知道视图将在何种上下文中显示。调用者负责设置正确的帧,自动调整掩码和类似属性。

UINavigationController方法想象一下:

// we are pushing new VC, view is accessed for the first time
pushedVC.view.frame = CGRectMake(...);

正在设置正确的框架,但-loadView仅在<{>> 之前被称为-setFrame:。所以在-viewDidLoad期间你有临时的非零帧,只是为了能够设置子视图和内部自动调整。在此之后,将为您设置正确的帧,并在-viewWillAppear:中设置最终帧。

答案 1 :(得分:13)

首先,loadView没有'默认'实现...该方法专门用于覆盖。我确实同意Apple的文档可能有点不清楚。但是,只要访问导航控制器的视图并且不存在视图(例如:loadView),就会默认调用UIView *view = viewController.view。它也可以手动调用。但在任何情况下,loadView都不会有正确的维度......事实上,这是不可能的。调用loadView以便父视图控制器首先获取视图,以便它可以适当地调整大小。然后,一旦获得视图,它就会调用viewDidLoad。这是他们可以使用的唯一代码路径,因为视图可以从loadView方法或nib加载,并且当从nib加载视图时,它们必须提供额外设置的位置。最后,父控制器将调整视图大小并仅在视图实际显示时调用viewWillAppear。例如,如果您在离开屏幕的navController上按下控制器,它将不会调用viewWillAppear,直到navController本身被放置在屏幕上。这样做是因为在控制器实际可见之前运行该代码毫无意义。这也是您只能在viewWillAppear方法中获得正确尺寸的原因。

现在,您注意到如果将控制器添加到标准控制器,则不会发生这种情况。这是因为视图控制器实际上并不打算包含其他视图控制器。现在在iOS 5中,他们明确支持使用容器视图控制器......它本质上是一个视图控制器,旨在包含其他视图控制器。他们在iOS 5中添加了一些“便利”方法来帮助解决这个问题,但这并不是绝对必要的。所有这些的要点是:如果要将一个视图控制器添加到另一个视图控制器,则必须手动设置对子视图控制器的所有适当调用(所有加载方法,旋转事件,内存警告等)。换句话说,您必须创建自己的容器视图控制器。但是,当你这样做时,请记住我之前所说的关于代码路径的内容。重要的是你按照Apple所做的相同顺序调用子控制器方法,或者东西不能正常工作。

以下是一些信息链接: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html - 向下滚动到:实现容器视图控制器

此处还有视图控制器生命周期,它将帮助您确定需要按哪种顺序进行调用:http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW1

我建议您阅读整个View Controller编程指南....您可以从那里获取大量信息:http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007457-CH1-SW1