UIViewController的生命周期

ViewController生命周期

alloc ->init-> initWithNibName -> loadView -> viewDidLoad -> viewWillAppear -> viewDidAppear -> viewWillDisappear -> viewDidDisappear -> dealloc

注意viewWillUnload和viewDidUnload已经在ios6被废弃了,因为Clearing references to views is no longer necessary。

注意1.没有viewWillLoad。

注意2.viewDidLoad和viewDidUnload并不是成对的。

 

ViewController是IOS开发中MVC模式中的C,ViewController是view的controller,ViewController的职责主要包括管理内部各个view的加载显示和卸载,同时负责与其他ViewController的通信和协调。在IOS中,有两类ViewController,一类是显示内容的,比如UIViewController、UITableViewController等,同时还可以自定义继承自UIViewController的ViewController;另一类是ViewController容器,UINavigationViewController和UITabBarController等,UINavigationController是以Stack的形式来存储和管理ViewController,UITabBarController是以Array的形式来管理ViewController。和Android中Activity一样,IOS开发中,ViewController也有自己的生命周期(Lifecycle)。

View的加载过程,如下图:

 

从图中可以看到,在view加载过程中首先会调用loadView方法,在这个方法中主要完成一些关键view的初始化工作,比如UINavigationViewController和UITabBarController等容器类的ViewController;接下来就是加载view,加载成功后,会接着调用viewDidLoad方法,这里要记住的一点是,在loadView之前,是没有view的,也就是说,在这之前,view还没有被初始化。完成viewDidLoad方法后,ViewController里面就成功的加载view了,如上图右下角所示。

在Controller中创建view有两种方式,一种是通过代码创建、一种是通过Storyboard或Interface Builder来创建,后者可以比较直观的配置view的外观和属性,Storyboard配合IOS6后推出的AutoLayout,应该是Apple之后主推的一种UI定制解决方案,通过IB或Storyboard创建view,在Controller中创建view后,会在Controller中对view进行一些操作,会出现如下代码:

 

视图的加载过程

AppDelegate.m

RootViewController *rootViewController = [[RooViewController alloc] init]; // 1

self.window.rootViewController = rootViewController; // 9

[rootViewController release];

 

-(id)init

{

  self = [super init]; // 2     里面用到了一个指定初始化方法指定到下面

  if(self){ // 5

   //NSLog(@"%@",self.view); //在创建视图控制器时,不要在视图控制器的初始化方法中做view相关的事情,一般在init方法中初始化一些数据,模型

  }

  return self; // 6

}

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

{

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

  if (self) {

    // Custom initialization

  }

  return self; // 4

}

一旦覆盖loadView,一定要创建一个视图给视图控制器,可以调用父类的loadview或者自定义一个view,否则的话我们视图的创建是失败的,有可能会引发循环调用的问题

- (void)loadView // 7

{

  //第一种方式:调用父类的loadview

  [super loadview];

  //第二种方式:自定义

  UIView *view = [[UIView alloc] initWIthFrame:[[UIScreen mainScreen] appllicationFrame]];

  view.backgroundColor = [UIcolor redColor];

  self.view = view;

  [view release];

      // add subview

}

 

- (void)viewDidLoad // 8

{

    [super viewDidLoad]; 

  // 1.view -> nil    2.getter method

  // NSLog(@"%@",self.view);

  // 访问网络

}

 

// 视图的出现与消失

-(void)viewWillAppear:(BOOL)animated

{

    [super viewWillAppear:(BOOL)animated];

}

 

-(void)viewDidAppear:(BOOL)animated{

    [super viewDidAppear:(BOOL)animated];

}

// 视图的卸载(6.0之前)

 

从图中可以看到,当系统发出内存警告时,会调用didReceiveMemoeryWarning方法,如果当前有能被释放的view,系统会调用viewWillUnload方法来释放view,完成后调用viewDidUnload方法,至此,view就被卸载了。此时原本指向view的变量要被置为nil,具体操作是在viewDidUnload方法中调用self.myButton = nil;

SecondViewController.h

@interface SecondViewController:UIViewController

@property (nonatomic,retain) UIView *subView;

@end

SecondViewController.m

- (void) loadView

{

  UIView *baseView = [[UIView alloc]initWIthFrame:[[UIScreen mainScreen] appllicationFrame]]; // 1

  baseView.backgroundColor = [UIColor yellowColor];

  self.view = baseView;

  [baseView release];

 

     // 全局的不要在下面release,他还要给其他人用

  _subView = [[UIView alloc]  initWithFreame:CGRect(60,100,200,200)]; // 1

  _subView.backgroundColor = [UIColor redColor];

  [self.view addSubview:_subView];  // 2

 

  // 局部变量出了这个方法就没了,意义在于给self.view

  UIView *otherView = [[UIView alloc]initWIthFrame:CGRect(110,350,100,100)]; // 1

  otherView.backgroundColor = [UIColor yellowColor];

  [self.view addSubview:otherView];  // 2

  [otherView release]; // 1

}

- (void) viewWillUnload    // 5.0~6.0   这里的view实际上指的就是baseView

{

  [super viewWillUnload];

}//视图控制器的视图将要卸载(这行过后视图控制器的view为nil)

- (void) viewDidUnload // 卸载时,self.view为nil会release一次subView,之后调用self.subView = nil再释放一次。

{

  [super viewDidUnload];

  // 系统自己判断了,然后释放了self.view -> nil  自己会release,会把它所加的对象都release一遍(otherView也会死掉) //1

  self.subView = nil; // 0

  // NSLog(@"%@",self.view); 不能这样做,因为self.view -> nil    getter方法   会引发[self loadView];

} // 视图控制器已经卸载,需要卸载掉其他的子视图(强引用)

- (void)didReceiveMemoryWarning // 6.0之后用这个

{

  [super didReceiveMemoryWarning];

      // 拿到应用程序的窗口

  // [UIApplication sharedApplication].keyWindow; 或 self.view.window   (window指AppDelegate里面创建的window,只有一个window)

  // NSLog(@"self.view.window : %@",self.view.window); 如果出现内存警告,则view已经deal,所以不能打印这句话

  if ([self.view window] == nil)// 当前的视图控制器中的视图不在当前窗口中

  {

    self.subView = nil;

    self.view = nil; // 6.0之前会帮我们写,之后要自己写 

  }   

}

- (void) dealloc

{

  self.subView = nil;

  [super dealloc];

}

@property(nonatomic,retain) UIView *view; // The getter first invokes [self loadView] if the view hasn't been set yet. Subclasses must call super if they override the setter or getter.

如果这个视图view尚未设置或初始化,那么只要第一次调用getter方法就会引发[self loadView]

- (void)loadView; // This is where subclasses should create their custom view hierarchy if they aren't using a nib. Should never be called directly.

如果没有用nib来创建的话,他会创建一个自定义的有层次结构的视图。

 

1、alloc                                  创建对象,分配空间

2、init (initWithNibName)        初始化对象,初始化数据

3、loadView                           当手动创建时,需要覆盖这个方法,如果 从nib载入视图,通常这一步不需要去干涉。除非你没有使用xib文件创建

4、viewDidLoad                      载入完成,可以进行自定义数据以及动态创建其他控件,加载网络请求的数据

5、viewWillAppear                  视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了

6、viewDidAppear                  视图已在屏幕上渲染完成

 

当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反

1、viewWillDisappear             视图将被从屏幕上移除之前执行

2、viewDidDisappear             视图已经被从屏幕上移除,用户看不到这个视图了

3、viewUnLoad                    

4、dealloc                             视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行

 

loadView和viewDidLoad的区别就是,loadView时view还没有生成,viewDidLoad时,view已经生成了,loadView只会被调用一次,而viewDidLoad可能会被调用多次(View可能会被多次加载),当view被添加到其他view中之前,会调用viewWillAppear,之后会调用viewDidAppear。当view从其他view中移除之前,调用viewWillDisAppear,移除之后会调用viewDidDisappear。当view不再使用时,受到内存警告时,ViewController会将view释放并将其指向为nil。

posted @ 2015-01-31 13:53  浅忆0  阅读(294)  评论(0编辑  收藏  举报