[轉]loadView/viewDidLoad/initWithNibName/awakeFromNib/initWithCoder的用法

作者:禚來強 郵箱:[email protected] 轉帖請保留 

 

每個ios開發者對loadView和viewDidLoad肯定都很熟悉,雖然這兩個函數使用上真的是非常簡單,但是和類似的initWithNibName/awakeFromNib/initWithCoder放在一起還是非常容易讓人混淆的. 

 

昨天看了下蘋果官方的相關文檔以及幾篇相關內容的網頁(一 二 三),其實這個內容以前也看過,似乎也搞清楚了,可還是忘了.好急性不如爛筆頭,這次一定要好好記下來. 

 

大前提是UIViewController有一個UIView.同時,需要釐清兩個概念,創建一個類和實例化一個類.在XCode中創建一個類和實例化一個類很容易區分,但是在IB(Interface Builder)中有時候就會迷糊.其實也很好區分,孤零零地創建了一個nib文件,沒有和其他可被實例化的類有直接或間接關係的時候,這個類或這些類(一個nib文件俺也可能包含多個類)是沒有機會被實例化的,所以這種情況只是通過ib創建了一個類,而沒有實例化.真正的實例化還需要通過在Xcode用代碼來讀取這個nib文件.知道這兩這的區別後這些方法也就容易辨認多了 

 

viewDidLoad其實沒什麼可混淆的,無論通過什麼途徑加載(Xcode或者IB,這裏的加載屬於實例化)完view後肯定會執行這個方法. (具體就是當前viewcontroller加載進當前窗口界面)

 

loadView需要分兩種情況.當你通過Xcode實例化一個類的時候就需要自己在controller中實現這個方法.而在IB中實例化就不需要實現它. (不理解禚的這句話是什麼意思)

 

initWithNibName這個方法是在controller的類在IB中創建,但是通過Xcode實例化controller的時候用的. 

 

awakeFromNib這個方法是一個類在IB中被實例化是被調用的.看了帖子發現大家都推薦使用viewDidLoad而不要使用awakeFromNib,應爲viewDidLoad會被多次調用(多次調用?哪來的多次調用,不理解…),而awakeFromNib只會當從nib文件中unarchive的時候纔會被調用一次.實際測試中發現,當一個類的awakeFromNib被調用的時候,那麼這個類的viewDidLoad就不會被調用了,這個感覺很奇怪. 

 

initWithCoder是一個類在IB中創建但在xocdde中被實例化時被調用的.比如,通過IB創建一個controller的nib文件,然後在xocde中通過initWithNibName來實例化這個controller,那麼這個controller的initWithCoder會被調用. 

 

 

如果你的對象是UIViewControler的子類,那麼你必須調用- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil;方法去調用NIB文件初始化自身,即使那沒有使用nib文件也會調用這個函數(默認情況下init方法已經爲你的做這件事情了),如果你調用這個方法,並傳遞的兩個參數爲空(nil),然後類會調用-loadView去讀取一個名字和你的UIViewController名字相同的nib文件,來初始化自身。如果沒有這樣的nib文件,你必須調用-setView:來設置一個self.view。或者重載-loadView 方法 

 

 

運行順序:本人已試過: 

viewDidLoad ->awakeFromNib ->viewWillAppear


另一篇:
http://haoxiang.org/category/all-about-ios/page/2/

loadView的用法


UIViewController的loadView

 

用UIViewController有一段時間了,才發現以前對loadView的理解完全不到位。

 

假如我們用Xcode新建一個View-based Application,在ViewController.m中加上

 

- (void) loadView {

NSLog(@"loadView Called");

}

 

再增加viewDidLoad,按照一般的情況,我們會有這樣的Code

 

- (void) viewDidLoad {

[super viewDidLoad];

UIButton *customButton = [UIButton buttonWith.....

......

[self.view addSubView:customButton];

}

 

現在打開MainWindow.xib,刪掉其中的ViewController,並在AppDelegate.m的

 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

 

裏增加ViewController的初始化

 

viewController = [[XXXViewController alloc] init];

 

編譯運行就有問題了。Console中不斷的輸出loadView Called!

 

仔細的閱讀loadView的文檔,才知道loadView不是這麼用的。

 

loadView在每一次使用self.view這個property,並且self.view爲nil的時候被調用,用以產生一個有效的self.view。這個接口原本是爲了讓我們自定義view用的。在不被subclass實現的情況下,也就是[super loadView]的效果,應該就是產生了一個有效的view,也就是一個空白的view。

 

在上面這種情況下,loadView被實現爲空(只有一條打印語句),而且我們沒有通過XIB初始化ViewController,所以在viewDidLoad被執行時,self.view是爲nil的。所以在執行[self.view addSubView:customButton]時,loadView被調用,用來產生一個有效的view,使得self.view不再爲nil。罷特,我們錯了(-_-!)。我們的loadView什麼也沒有做,於是就出現了上面的情形,不斷的調用一個什麼都不做的loadView….

 

當然,我們只要在loadView中增加一句[super loadView]就沒有問題了。但這並不是Cocoa的設計者所期望的。

 

loadView僅僅應該在開發者希望自行通過編碼而不是Interface Builder定製view的時候被實現,而且不應該在其中調用[super loadView],你的loadView中應該有self.view = …這樣的行爲

 

如果僅僅是想要在當前view上增加一些UIButton或是UILabel,應該在viewDidLoad裏去做,此時不要實現自己的loadView。

 


下面這部分是UIViewController.h文件中對以上方法的解釋:

 

// The designated initializer. If you subclass UIViewController, you must call the super implementation of this method, even if you aren’t using a NIB.

// (As a convenience, the default init method will do this for you, and specify nil for both of this methods arguments.) In the specified NIB, the File’s Owner proxy should

// have its class set to your view controller subclass, with the view outlet connected to the main view. If you invoke this method with a nil nib name, then this class’ -loadView 

// method will attempt to load a NIB whose name is the same as your view controller’s class. If no such NIB in fact exists then you must either call -setView: before -view is 

// invoked, or override the -loadView method to set up your views programatically.

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

 

@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.

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

- (void)viewDidLoad; // Called after the view has been loaded. For view controllers created in code, this is after -loadView. For view controllers unarchived from a nib, this is after the view is set.

 


下面是我寫的代碼無示例(只測試了initWithNibName,loadView,viewDidLoad)

ExploreInitWithNibNameLoadViewAndViewDidLoad.zip (30.54 kb)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章