[置顶] iOS之App循环执行ViewDidLoad

App循环执行ViewDidLoad

APP 运行,先跑init 然后跑

 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 来查找XIB中有没有视图view。如果有,则不会再走loadView。如果这个时候你的VC是没有xib的,哪么显然走这个方法后,是找不到任何view的,即self.view 仍为nil.然后,就跑loadview,这个时候会被触发,如果在loadView中,什么也不做,也不实例化一个View。哪么程序继续跑到viewDidLoad里,如果这里还是没有实例化VIEW。哪么这个VC就没有视窗。在这里很多时侯会出现一个误区 (死循环)

好,下面来解释一下死循环的条件。
1、没有XIB。
2、ViewController中的loadView方法中没有做任何实例化self.view的操作。如:
-(void)loadView
{
   没有执行以下两种方式中的其中一种。
    //方式一:实例化时使用[supper loadView];    
    //方式二 : self.view = [UIView alloc]....       
}
3、在viewDidLoad中调用了self.view。

只要这三个条件同时满足,必定死循环。方式一时,调用了[Supper LoadView] 这个时候由父类产生了一个(0,20,Width,height )。这里的宽高根据是IPAD,还是IPHONE不同而不同,但原点坐标一定是(0,20)即去除状态条。方式二,没有对self.view作任可赋值,所以使得self.View = nil;
在条件二满足的情况下,程序运行到步骤三,这个时候,如果在这里调用了self.View。因为self.View在步骤二中为空,所以又回调到了loadView来,但因loadView中没有对self.View作实例化,于是在跑完loadView后,又继续跑viewDidLoad,但因ViewDidLoad中又没有实例化的情况下,使用了self.View.因此就出会现来回调用的现象。

好了,知疲知已方能百战百胜。解决死循环。

在步骤二中下手,处理方式有三:
a、把整个-(void)loadView 屏蔽掉。让父类自己来创建一个VIEW。这个是最常见的,因为ViewController产生的时候默认代码中是把这段代码给注释了的。
b、在loadView中添加一句[Supper LoadView];个人不太建议这样写吧,当然如果你理解了VIEW之间的关系,也无所谓。
c、在loadView中,使用已实例化的View对Self.View进行赋值。注:是使用=号赋值,而不是使用[self.view addSubView]因为此时self.view 是空指针,执行ADD操作会崩溃的。

另外,也可以在步骤三中下手,即使在步骤二中没有任何实例化VIEW操作,但在步骤三中进行了相应的实例化操作,仍可以解决的。这就是通常我们为什么不打开-loadView的注释,而直接在ViewDidLoad中进行添加视窗。

 好了,上面的死循环介绍完了,顺便对使用下面两个方法来实例化视窗注意的地方。
 1、[[UIScreen mainScreen] bounds]    返回的Rect是以(0,0)为坐标原点的大小,即包括了状态栏。
2、[[UIScreen mainScreen]applicationFrame] 返回的Rect是(0,20)为坐标点的大小,不包括状态栏。通常使用[supper loadView]所产生的的VIEW也就是这个所产生的。

如果在loadView中,调用[supper loadview];或使用self.view =[[ [UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame] ]autorelease]; 这样在父子层之间使用AddSubView,你会看到一个偏移量为20的层叠视窗。原因就是这两个方式返回的RECT的原点都是(0,20);
DEMO:
A  Viewcontroller
中的
 - (void)loadView
{
    [super loadView];
    //self.view  = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen]applicationFrame]] autorelease];
    
    //self.view  = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 400)]; 
                   
    self.view.backgroundColor = [UIColor greenColor];
   
    BVC *bvc = [[BVC alloc]init];
    NSLog(@"bvc View %@",bvc.view);
    [self.view addSubview:bvc.view];


B ViewController 中的
 - (void)loadView
{
   
    [super loadView];
    //self.view  = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen]applicationFrame]] autorelease];
    //self.view  = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 400)]; 
    
    self.view.backgroundColor = [UIColor redColor];
    
    CVC *cvc = [[CVC alloc]init];
    [self.view addSubview:cvc.view];
    

c ViewController中的
 - (void)loadView
{
    [super loadView];
    //self.view  = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen]applicationFrame]] autorelease];
    //self.view  = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 300)]; 
 
    self.view.backgroundColor = [UIColor blueColor];

最后运行效果:
[置顶] iOS之App循环执行ViewDidLoad_第1张图片
如果想子视图直接复盖父视图的大小可以使用[[UIScreen mainScreen] bounds]或者直接用UIVIEW实例化时指定原点。



init只是加载就行,有没有xib无所谓;

但是initWithNibName需要xib文件,如果该文件不存在则报错:



===================================================

  关于 initWithNibName 和 loadNibNamed 的区别和联系。之所以要把这两者来一起讲,我觉的我也有点困惑,到底用那种?其实真正搞清楚了他们之间的差别,就不会这么迷惘了。因为这两个方法,根本就不是一路货色。

 

既然,是要说明这2个方法,那就着重将区别吧。

但是第一步,还是要罗嗦一下,他们的联系可以使用此方法加载用户界面(xib文件)到我们的代码中,这样,可以通过操作这个加载进来的(xib)对象,来操作xib文件内容。

 

下面进入主题,谈区别:

1. ShowViewController的initWithNibName方法

ShowViewController* showMessage = [[ShowViewController alloc]

 

                        initWithNibName:@"ShowViewController" bundle:nil];

 

       self.showViewController = showMessage;

 

       [showMessage release];

 [置顶] iOS之App循环执行ViewDidLoad_第2张图片

 

 

2.VideoCellControllerloadNibNamed方法

NSArray * nib = [[NSBundle mainBundle]loadNibNamed:@"Save3ViewController" 

                              owner:self options:nil] ;

self.showViewController= [nib lastObject];

[nib objectAtIndex:0];

[置顶] iOS之App循环执行ViewDidLoad_第3张图片

 

总结:

只看他们初始化,那可能感觉是一样的。但是如果,打开分别看xib的关系的时候,才恍然大悟,原来他们的集成类都不一样。

1.initWithNibName要加载的xib的类为我们定义的视图控制器类 

  loadNibNamed要加载的xib的类为NSOjbect

(比如:甲,乙都买了一个iPhone,但是,甲的是自己的钱,而乙用的是某某的钱)

 


2.加载方式不同

 initWithNibName方法:是延迟加载,这个View上的控件是 nil 的,只有到 需要显示时,才会不是 nil

loadNibNamed方法:即时加载,用该方法加载的xib对象中的各个元素都已经存在。

(认真理解这句帮规:whenusing loadNibNamed:owner:options:, the File's Owner should be NSObject, themain view should be your class type, and all outlets should be hooked up to theview, not the File's Owner.

 [置顶] iOS之App循环执行ViewDidLoad_第4张图片

 


 


===================================================

IOS-UIViewController的生命周期

当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序
1、 alloc                                   创建对象,分配空间
2、init (initWithNibName) 初始化对象,初始化数据
3、loadView                          从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
4、viewDidLoad                   载入完成,可以进行自定义数据以及动态创建其他控件
5、viewWillAppear              视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、viewDidAppear               视图已在屏幕上渲染完成

当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
1、viewWillDisappear            视图将被从屏幕上移除之前执行
2、viewDidDisappear             视图已经被从屏幕上移除,用户看不到这个视图了
3、dealloc                                 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

关于viewDidUnload :在发生内存警告的时候如果本视图不是当前屏幕上正在显示的视图的话, viewDidUnload将会被执行,本视图的所有子视图将被销毁,以释放内存,此时开发者需要手动对viewLoad、viewDidLoad中创建的对象释放内存。 因为当这个视图再次显示在屏幕上的时候,viewLoad、viewDidLoad 再次被调用,以便再次构造视图。



initWithNibName的初始化问题

在开发过程中,几次碰到在initWithNibName:nibNameOrNil方法里加载组件或者初始化一些值时,都跟没设置一样,查了一些资料才发现,原来initWithNibName:nibNameOrNil得执行顺序是这样子的

supper :  
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{// 第2步--start
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        set   param=@“supper-A”
        NSLog(@“A-initNIb”);
    }// 第2步--end
}

viewDidLoad
{
    [super viewDidLoad]; // 第3步--step3
    NSLog(@“A-view”);
    NSLog(param); // 第3步--step4
} 
sub:  
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // 入口
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; // 第1步
    // 第4步--start
    if (self) {
        set   param=@“sub-B”
        NSLog(@“B-initNIb”);
    }
    // 第4步--end
}

viewDidLoad // 第3步入口     // 第5步入口
{
    [super viewDidLoad]; // 第3步--step 1
    NSLog(@“B-View”);
    NSLog(param);// 第3步--step 2 这里的param是继承父类,与第4步的param赋值无关
}


执行sub时输出顺序:

A-initNIb   

A-view

supper-A

B-View

supper-A

B-initNIb


sub-initWithNibName: 里调用supper的initWithNibName:

superclass的initWithNibName方法结束,表示nib文件已加载,则调用sub的 viewDidLoad方法。于是应调用[subclass viewDidLoad]方法。( 关键:initWithNibName方法结束,表示nib文件已加载,会自动调用nib文件的File’sowner所指向的 viewDidLoad方法,最后才是initWithNibName方法剩余的代码)


subclass的viewDidLoad方法又调用了supclass的viewDidLoad方法。

最后才是initWithNibName方法剩余的代码


结论,你在sub里面设置的param=sub-B,并没有起作用输出,因为,在设置之前,sub的view已经执行过了,为了避免这样可以改成

[cpp]  view plain copy print ?
  1. sub  
  2. viewDidLoad  
  3. {  
  4. NSLog(@“B-View”);  
  5. NSLog(param);  
  6. [super viewDidLoad];  
  7. }  
  8.   
  9. - (void)viewDidLoad{  
  10. [selfsetWords:@” pleaseanswer the door”];  
  11. [super viewDidLoad];  
  12. }  


若没有指定file's owner,输入结果如下:

[置顶] iOS之App循环执行ViewDidLoad_第5张图片



[置顶] iOS之App循环执行ViewDidLoad_第6张图片


[置顶] iOS之App循环执行ViewDidLoad_第7张图片




部分资料源自互联网。


你可能感兴趣的:([置顶] iOS之App循环执行ViewDidLoad)