awakeFromNib 與 initWithNibName:bundle:

程式大了一些之後,我們常常會需要切換不同的 view 元件,一般來說,會把幾個主要的 view 以及它的 controller 包到獨立的 nib 檔中。一來方便管理,不會在 MainMenu.nib 中看到一堆 view、controller,甚至其他的 formatter 之類的。二來,可以依需要動態載入、釋放這些 object,降低佔用的系統資源。

而一般 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,並在裡面做初始化的動作。

Contents

comments powered by Disqus