星期三, 四月 28, 2010

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

標籤: , ,

星期四, 四月 22, 2010

Cocoa 手勢支援

在 Macbook Air 推出之後,Apple 就多了手勢操作這項功能,但是這項功能雖然在 10.5 就有了,不過卻直到 10.6 才在 Apple 的 Document 中出現。而要在 10.5 中使用這項功能的話,其實也很簡單,只要實作 10.6 的 Document 裡面出現的幾項 method 即可,也就是下面五個 method:
  • - (void)magnifyWithEvent:(NSEvent *)event;
  • - (void)rotateWithEvent:(NSEvent *)event;
  • - (void)swipeWithEvent:(NSEvent *)event;
  • - (void)beginGestureWithEvent:(NSEvent *)event;
  • - (void)endGestureWithEvent:(NSEvent *)event;
不過除非要自己抓取新的手勢,不然主要只要實作 magnifyWithEvent、rotateWithEvent、swipeWithEvent 這三個即可。

這三個手勢的詳細操作,可以參考 10.6 的 Document,在 10.5 都相容,只有 magnifyWithEvent 要特別處理一下。

magnifyWithEvent 的標準用法如下(Apple Document):
- (void)magnifyWithEvent:(NSEvent *)event {
[resultsField setStringValue:
[NSString stringWithFormat:@"Magnification value is %f", [event magnification]]];
NSSize newSize;
newSize.height = self.frame.size.height * ([event magnification] + 1.0);
newSize.width = self.frame.size.width * ([event magnification] + 1.0);
[self setFrameSize:newSize];
}
但是在 10.5 上,NSEvent 沒有 magnification 這個 method,所以必須自己擴充,code 如下(ref):
#pragma mark defines for 10.6 api not documented in 10.5
#ifndef MAC_OS_X_VERSION_10_6
enum {
/* The following event types are available on some hardware on 10.5.2 and later */
NSEventTypeGesture = 29,
NSEventTypeMagnify = 30,
NSEventTypeSwipe = 31,
NSEventTypeRotate = 18,
NSEventTypeBeginGesture = 19,
NSEventTypeEndGesture = 20
};

@interface NSEvent(GestureEvents)
/* This message is valid for events of type NSEventTypeMagnify, on 10.5.2 or later */
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 - (float)magnification; // change in magnification. #else - (CGFloat)magnification; // change in magnification. #endif @end #endif

這段 code 也把 10.5 中 NSEvent 欠缺的 type id 補齊了,所以如果想要支援手勢操作,最好都把這段 code 貼上來用吧。

標籤: ,

星期日, 五月 24, 2009

NSNumber 與 NSInteger

在 Mac OSX 10.5 中新增加了 NSInteger 這個東西,但是這下就會跟 NSNumber 搞混,到底要用哪個?

基本上,NSInteger(以及類似的 NSUInteger)是為了解決在 32-bit/64-bit CPU 架構下,int 長度不同的問題,它的定義如下:

#if __LP64__ || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
也就是說,NSInteger 只是用 typedef 包裝過的 int/long,它是個基本資料型別(data type)。

NSNumber 則是個不折不扣的 Objective-C 類別,因此這兩者的使用時機就很明顯了,當你要把 integer 放到 Obj-C 的集合,例如 NSArray/NSSet 時,請用 NSNumber,不然其他的時候用 NSInteger 就好了。

標籤: , , ,

星期四, 十二月 13, 2007

CocoaCast

有朋友在 PTT 的 MacDev 版詢問要怎麼在 Xcode 上寫 C++ 和 Java,其實問題內容是他不知道怎麼開始使用 Xcode。雖然我之前翻的 Become an Xcoder 有稍微介紹了 Xcode,但畢竟不是專門講這部份,說不定應該要來寫一篇簡單的教學?

不過後面 anpig 兄倒是推薦了一個不錯的 podcast 資源:CocoaCast,內容看起來相當豐富,有興趣的朋友歡迎訂閱。

標籤: ,

星期二, 十二月 11, 2007

在 Mac 上使用 VTK

VTK - Visualization Toolkit 是一套在醫學影像上不少人用的 Open Source 函式庫,因為課程需要所以前陣子找了要怎麼在 Mac 上使用的一些資料。

Installing VTK on Mac OS X - 教你怎麼在 Mac 上編譯並安裝 VTK。不過他是直接安裝,像我這種喜歡用套件管理系統的人,可能會比較喜歡用 Fink 來安裝。
幸運的是,Fink 中已經有了 VTK,只要啟用了 unstable 的套件之後就可以看到三個名為 vtk-py23/24/25 的套件,這三個套件都是 VTK,只是個別用來搭配 Python 2.3/2.4/2.5 罷了,選一個裝就可以了。不幸的是,VTK 本身有支援 Cocoa,但是預設是沒有開啟,而目前 Fink 套件樹中的也沒有打開這功能,而且他沒有包到目前最新的版本(5.0.3)。

所以我根據 Fink 中 VTK 的設定檔,把 Cocoa 支援打開,包了 VTK-5.0.3,設定檔可以由此下載。下載之後的檔案是個 zip 檔,其中包含了三個檔案,把它們放到 {fink_path}/fink/dists/local/main/finkinfo 中,然後把 VTK-5.0.3 的原始碼(下載)放到 {fink_path}/src 下,然後設定一下讓 Fink 去讀取本地的套件,應該就可以在套件樹中看到 vtk-py23/24/25 這三個套件,而且版本都是 5.0.3,最後下指令讓它編譯安裝(我是使用 Fink Commander 直接點選),等它編完安裝完就可以用了。

想要玩的朋友請接著看以下三篇文章,應該就可以順利使用 Cocoa 搭配 VTK 使用了。
Cocoa for Scientists (Part XIV): Beginning 3D Visualization - MacResearch
Cocoa for Scientists (Part XV): Continuing 3D Visualization - MacResearch
Cocoa for Scientists (Part XVI): Finalizing 3D Visualization - MacResearch

最後附上我寫的作業畫面:

標籤: , , ,