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實例化時指定原點。
就這樣吧,希望這些對你有幫助。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM