UIViewController 初始化和加载顺序 [英] Order of UIViewController initialization and loading

查看:19
本文介绍了UIViewController 初始化和加载顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Mac 和 iPhone 上的 UI 编程还很陌生,并且遇到了一些让我感到困惑的事情.

一个 UIViewController 有 3 个方法来初始化它和它的视图:

  1. init(和类似 init 的方法)
  2. 加载视图
  3. viewDidLoad(委托方法)

我希望这些会按上述顺序发生.首先 UIViewController 被其他一些对象分配,然后立即调用 init(或其他一些 init 方法,如 initWithStyle).

只有在对象初始化后,我才会期望它调用自己的 loadView 函数,之后视图在加载后调用 viewDidLoad 委托方法.

这不会发生,例如:

@implementation UIViewControllerSubclass- (id)init {NSLog(@"0");如果(自我= [超级初始化]){NSLog(@"1");}回归自我;}- (void)loadView {[超级加载视图];NSLog(@"2");}- (void)viewDidLoad {[超级viewDidLoad];NSLog(@"3");}@结尾

产生控制台输出:

<预><代码>0231

因此,loadView 和 viewDidLoad 方法不能进行委托调用,因为委托通常在调用 [super init] 之后设置,后者(如上所示)在 loadView 和 viewDidLoad 之后调用已经运行:

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] init];[viewController setDelegate:self];

如果我想以某种方式运行设置 ViewController 的代码,并在运行时通知委托,代码是否应该驻留在 init 方法中?loadView存在的原因难道不是为了让这样的代码在适当的时候运行吗?

在我看来,我必须创建一个新的 initWithDelegate 方法,该方法在调用 [super init] 之前设置委托 ivar ,这是对的,还是我以错误的方式进行处理?

提前致谢:)

解决方案

iPhone 上的视图加载系统是这样工作的:

当您初始化视图控制器(使用 -init 或 -initWithNibName:bundle:)时,它实际上并没有创建和初始化视图.当您第一次调用 -view 时,它会调用 -loadView.默认情况下,-loadView 只是从 xib 文件 (nibName) 加载视图.但是,如果您覆盖它,则您负责创建视图并将其分配给视图控制器的视图属性.举个例子:

- (void)loadView{UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];//添加子视图self.view = 视图;【查看发布】;}

每次创建视图时,这与视图变得可见并显示在屏幕上不同,它调用 -viewDidLoad.(-viewDidAppear/-viewDidDisappear 用于屏幕上视图的可见性)

由于我们已经偏离了轨道,让我们考虑内存管理.当视图离屏时,系统会自动将视图控制器的视图属性设置为 nil.问题是该视图的所有子视图都在泄漏.怎么会这样?好吧,每个子视图的保留计数是 2(视图保留子视图,并且您的视图控制器有一个出口/ivar).当视图为 nil 时,该视图的保留计数为 1.如果视图未显示,则视图停留是没有意义的,因此您在 -viewDidUnload 中将其设置为 nil(这是一个钩子)每当视图设置为 nil 时).

I'm fairly new to UI programming on the Mac and iPhone, and I've run across something that somewhat puzzles me.

A UIViewController has 3 methods that involve the initialization of it and its view:

  1. init (and init-like methods)
  2. loadView
  3. viewDidLoad (delegate method)

I'd expect these to occur in the order above. First UIViewController is alloc'ed by some other object, then init is immediately called (or some other init method, like initWithStyle).

Only once the object is initialized would I expect it to call its own loadView function, after which the view, once loaded, calls the viewDidLoad delegate method.

This doesn't happen, for instance:

@implementation UIViewControllerSubclass

- (id)init {
        NSLog(@"0");
    if (self = [super init]) {
        NSLog(@"1");
    }
    return self;
}

- (void)loadView {
    [super loadView];
    NSLog(@"2");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"3");
}

@end

Produces the console output:

0
2
3
1

The loadView and viewDidLoad methods, therefore, cannot make delegate calls, as the delegate is usually set after the call to [super init], which (as shown above) is called after loadView and viewDidLoad have run:

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] init];
[viewController setDelegate:self];

If I want to run code that sets up the ViewController in some way, notifying the delegate as it goes, should the code reside in the init method? Isn't the reason for loadView existing to allow such code to be run at the appropriate moment?

It looks to me like I'll have to create a new initWithDelegate method which sets the delegate ivar before calling [super init], is this right, or am I going about this the wrong way?

Thanks in advance :)

解决方案

The view loading system on the iPhone works like this:

When you initialize a view controller (either with -init or -initWithNibName:bundle:), it doesn't actually create and initialize the view. When you call -view for the first time, it calls -loadView. By default, -loadView just loads the view from the xib file (nibName). If you override this, though, you're responsible for creating the view and assigning it to the view controller's view property. As an example:

- (void)loadView
{
   UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
   // add subviews 
   self.view = view;
   [view release];
}

Every time you create the view, which is different from the view becoming visible and showing onscreen, it calls -viewDidLoad. (-viewDidAppear/-viewDidDisappear is for the visibility of the view on-screen)

Since we're already off-track, let's consider memory management. When the view is offscreen, the system will automatically set the view property of a view controller to nil. The problem is that all the subviews of that view are leaking. How so? Well, the retain count for each subview is 2 (views retain subviews, and your view controller has an outlet/ivar to it). When the view is nil, the retain count of that view is 1. It doesn't make sense for a view to stick around if a view isn't showing, so you set it to nil in -viewDidUnload (which is a hook for whenever the view is set to nil).

这篇关于UIViewController 初始化和加载顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆