UIViewController加载和卸载过程

来源:互联网 发布:sql注入攻击网站 编辑:程序博客网 时间:2024/04/30 20:07

加载过程:

一般情况下调用 init方法或者调用initWithNibName方法实例化UIViewController, 不管调用哪个方法都为调用initWithNibName(方法定义如下)

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

接着会调用loadView方法来生成UIViewController.view

- (void)loadView

然后调用 viewDidLoad方法

- (void)viewDidLoad

如果loadView不能生成UIViewController.view系统将会反复调用loadView及viewDidLoad方法, 并且最终调用[super loadView] 方法返回UIViewController.view

然后依次调用如下2个方法, 这2个方法也十分重要, 在UINavigationController的POP操作后有时将要显示的UIViewController中的View如果并没有释放(在其他地方retain了) , UIViewController将不会调用上面的三个方法(initWithNibName,loadView,viewDidLoad) 而会调用下面这2个方法

- (void)viewWillAppear:(BOOL)animated;

- (void)viewDidAppear:(BOOL)animated;

在iOS5.0中还添加了2个函数:

- (void)viewWillLayoutSubviews ;

- (void)viewDidLayoutSubviews;

另外如果你这样写:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];

self.view = view;

[view release];

// Custom initialization

NSLog(@"initWithNibName");

}

return self;

}

那么loadView和viewDidLoad 方法将不会被调用



卸载过程:

- (void)viewWillDisappear:(BOOL)animated;

- (void)viewDidDisappear:(BOOL)animated;

- (void)viewWillUnload;//iOS5.0添加

- (void)viewDidUnload;

- (void)dealloc;

PS: 当程序收到内存不足的警告后, 程序内存中的所有的UIViewController都将会收到didReceiveMemoryWarning调用消息. 目的是将当前不显示的UIViewController中的view释放掉(不会调用UIViewController的dealloc方法), 所以当该UIViewController再次显示的时候又要生成一次, 此时它会调用loadView-> viewDidLoad ->viewWillAppear等, 这时最容易造成内存泄漏!

- (void)didReceiveMemoryWarning;

- (void)viewWillUnload;//iOS5.0添加

- (void)viewDidUnload;



另附一篇很有价值的文章:

http://stackoverflow.com/questions/5069978/didreceivememorywarning-viewdidunload-and-dealloc

Some corrections and suggestions:didReceiveMemoryWarning practicesAs you said, the controller's default implementation of didReceiveMemoryWarning releases its view if it is 'safe to do so'. While it's not clear from Apple's documents what 'safe to do so' means, it is generally recognized as it has no superview (thus there is no way that the view is currently visible), and itsloadView method can rebuild the entire view without problems.The best practice when you override didReceiveMemoryWarning is, not to try releasing any view objects at all. Just release your custom data, if it is no longer necessary. Regarding views, just let the superclass's implementation deal with them.Sometimes, however, the necessity of the data may depend on the state of your view. In most cases, those custom data is set in viewDidLoad method. In these cases, 'safe to release custom data' means that you know that loadView and viewDidLoad will be invoked before the view controller uses the custom data again.Therefore, in your didReceiveMemoryWarning, call the superclass implementation first, and if its view is unloaded, then release the custom data because you know that loadView and viewDidLoad will be invoked again for sure. For example,- (void)didReceiveMemoryWarning {    /* This is the view controller's method */    [super didReceiveMemoryWarning];    if (![self isViewLoaded]) {        /* release your custom data which will be rebuilt in loadView or viewDidLoad */    }}Be careful not to use self.view == nil, because self.view assumes that the view is needed for someone and will immediately load the view again.viewDidUnload methodviewDidUnload is called when the view controller unloaded the view due to a memory warning. For example, if you remove the view from the superview and set the view property of the controller tonil, viewDidUnload method will not be invoked. A subtle point is that even if the view of a view controller is already released and set to nil by the time the controller receivesdidReceiveMemoryWarning, so actually there is no view to unload for the controller,viewDidUnload will be invoked if you call the superclass's implementation ofdidReceiveMemoryWarning.That's why it's not a good practice to manually set the view property of a view controller to nil. If you do, you may better send a viewDidUnload message as well. I guess your understanding ofviewDidUnload is more desirable, but apparently it's not the current behavior.Popping view controllersIf you mean 'removing from the superview' by 'popping', it does decrease the retain count of the view, but not necessarily deallocate it.If you mean popping out from a UINavigationController, it actually decrease the retain count of the view controller itself. If the view controller is not retained by another object, it will be deallocated, desirably with its view. As I explained, viewDidUnload will not be invoked this time.Others…Technically, the retain count may not go down to zero. The object is more likely to be just deallocated without setting the count to zero beforehand.Just to make sure, the view controller itself is normally not deallocated by default behaviors due to the memory warning.—————————————————————————————————————————-didReceiveMemoryWarning…Action – Release anything you do not need, likely to be undoing what you might have set up in viewDidLoad.This is wrong. Anything that you recreate in viewDidLoad should be released (and set to nil) inviewDidUnload. As you mention below, didReceiveMemoryWarning is also called when the view is visible. In didReceiveMemoryWarning, you should release stuff like caches or other view controllers you are holding on to that can be recreated lazily the next time they are required (i.e., by implementing their getter manually).viewDidUnload…Action – generally any IBOutlets you release in dealloc, should also be released (and references set to nil) in this method. Note that if the properties are set to retain, then setting them to nil will also release them.Correct. Generally, everything you create in viewDidLoad and all IBOutlets that are declared asretain should be released and set to nil here.dealloc…Action – release all objects that have been retained by the class, including but not limited to all properties with a retain or copy.Correct. It's worth noting that this includes all objects you handle in viewDidUnload because the latter is not implicitly called in the dealloc process (AFAIK, not entirely sure). That's why it is essential to set all releases objects to nil in viewDidUnload because otherwise you risk releasing something twice (first in viewDidUnload, then again in dealloc; if you set the pointer to nil, the release call indealloc will have no effect).Popping View Controllers and MemoryQuestion 2 – Does popping a view remove it from memory?Not necessarily. That is an implementation detail that you should not be concerned about. Whatever the current practice is, Apple could change it in the next release.


zz:

http://willonboy.tk/?p=518


原创粉丝点击