在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也就是這個所產生的。
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];
}
{
[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];
}
{
[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];
}
{
[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實例化時指定原點。
就這樣吧,希望這些對你有幫助。
