zoukankan      html  css  js  c++  java
  • IOS 的loadView 及使用loadView中初始化View注意的问题。(死循环并不可怕)

    在XCode 4.2后,我基本上的应用都不使用Xib文件了,虽然xib文件有很多好趣,可以快速免代码构建视窗,可以减少好多代码构建带来的麻烦,其实能用xib还是不错的,主要是我的机器打开xib来编辑时太慢了,跑不动了,老古董 的机器了,所以不怎么喜欢xib了(个人原因)。有人说xib会让代码跑起来效率慢,真的是这样吗?从理论上来看,APP要运行,先读INFO.PLIST文件,然后找到MAINWINDOW 的XIB,然后解释XIB中的代码来演变成OC代码进行实例化。而用普通代码构建,直接使用代码CODE而不用翻译XIB中的数据,省了一个步骤,或许就是这相原因吧。好了,这个先别讨论了,回到loadView,每一个VC(ViewController)都会生成一个loadview方法,当然,很多情况下都不怎么在这个方法中来写视窗,而是在ViewDidLoad中来写。先看看loadView调用的触发条件吧。


    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];

    最后运行效果:

    如果想子视图直接复盖父视图的大小可以使用[[UIScreen mainScreen] bounds]或者直接用UIVIEW实例化时指定原点。
    就这样吧,希望这些对你有帮助。
  • 相关阅读:
    boost之实用工具
    boost之内存池
    boost之智能指针
    boost之日期date_time
    boost之时间timer
    boost之网络通信
    boost之定时器和io_service
    【Linux 线程】线程同步《一》
    【Linux 线程】常用线程函数复习《四》
    【Linux 线程】常用线程函数复习《三》
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3123005.html
Copyright © 2011-2022 走看看