awakeFromNib 與 initWithNibName:bundle:
程式大了一些之後,我們常常會需要切換不同的 view 元件,一般來說,會把幾個主要的 view 以及它的 controller 包到獨立的 nib 檔中。一來方便管理,不會在 MainMenu.nib 中看到一堆 view、controller,甚至其他的 formatter 之類的。二來,可以依需要動態載入、釋放這些 object,降低佔用的系統資源。
而一般 view nib 檔中除了 view 之外,會把 File's Owner 指定為某個 controller 的類別,而這個類別通常是繼承自 NSViewController。
然後我們就可以在程式中使用
於是我們開心的在 MyViewController.m 裡面實作 awakeFromNib,在裡面初始化一些 UI 元件,一切依然很美好,然後我們利用
不過問題來了,如果我們要在把 view 顯示出來之前對 controller 先做些事,就會發現:awakeFromNib 還沒有被呼叫過!所以裡面的初始化都還沒做!
整個流程的問題出在,awakeFromNib 會在所有存在 nib 檔中的物件被解開之後,發送給 "所有這些被解開的物件",而 "這些物件" 並不包括我們的 controller,因為它是我們在別的地方 alloc 出來的!也就是說,MyViewController 並不會在 [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil]; 之後接收到 awakeFromNib。因此,初始化的適當地點是,自己實作 MyViewController 的 initWithNibName:bundle: method,並在裡面做初始化的動作。
而一般 view nib 檔中除了 view 之外,會把 File's Owner 指定為某個 controller 的類別,而這個類別通常是繼承自 NSViewController。
然後我們就可以在程式中使用
MyViewController * controller = [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil];來載入這個儲存在 nib 檔中的 view。
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil是 NSViewController 提供的一個 method,用來載入存在 nib 檔中的物件,然後我們就可以對 controller 下操作的命令,一切看起來都很美好。
於是我們開心的在 MyViewController.m 裡面實作 awakeFromNib,在裡面初始化一些 UI 元件,一切依然很美好,然後我們利用
[placeHolder addSubview:[controller view]];來把 MyView 顯示在某個 view 裡面,運作正常,美好的不得了。
不過問題來了,如果我們要在把 view 顯示出來之前對 controller 先做些事,就會發現:awakeFromNib 還沒有被呼叫過!所以裡面的初始化都還沒做!
整個流程的問題出在,awakeFromNib 會在所有存在 nib 檔中的物件被解開之後,發送給 "所有這些被解開的物件",而 "這些物件" 並不包括我們的 controller,因為它是我們在別的地方 alloc 出來的!也就是說,MyViewController 並不會在 [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil]; 之後接收到 awakeFromNib。因此,初始化的適當地點是,自己實作 MyViewController 的 initWithNibName:bundle: method,並在裡面做初始化的動作。

