跳轉到內容

Cocoa 程式設計/Objective-C 基礎

來自華夏公益教科書,開放的書籍,為開放的世界

Objective-C 是 Cocoa 應用程式的原生語言。它是 ANSI C 的面向物件超集,允許開發人員在程式中包含“純 C”語句和程式碼。任何 ANSI C 程式都是有效的 Objective-C 程式。

Cocoa 中使用的 Objective-C 與“純”Objective-C 有些不同,因為 Cocoa 執行時系統定義了一個新的根類,NSObject。所有 Cocoa 物件都應該是 NSObject 的後代,以便從其改進的記憶體管理模型中獲益。

NSObject 在標頭檔案 <Foundation/NSObject.h> 中定義。

NSObject 生命週期

[編輯 | 編輯原始碼]

要建立一個 NSObject,向其類傳送 allocnew 訊息

id anObject = [NSObject new];  // Creates and returns an initialized object

id anotherObj = [NSObject alloc];   // Not yet ready for use...
anotherObj = [anotherObj init];     //...now it is.

// good style: combine alloc and init:
id oneMoreObj = [[NSObject alloc] init];  // identical to using new

儘管“new”和“alloc 後跟 init”方法看起來相同,但 Apple 文件似乎更喜歡後一種方法。這使開發人員能夠分別覆蓋 allocinit 以實現特定結果(如果需要)。

請注意,初始化物件有時可能會失敗:例如,包含初始化資料的檔案可能不可用。在這種情況下,init 將返回 nil。因此,在使用物件之前始終檢查 init 的返回值!

物件初始化後,就可以使用了。要使用物件,向其傳送訊息

[anObject aMessage];

如果物件理解該訊息,它將對其做出反應。否則,將生成一個陷阱。

當不再使用物件時,必須將其釋放。要釋放物件,向其傳送 release 訊息。

[anObject release];

這將導致物件的銷燬(除非它仍在其他地方使用,請參閱Cocoa 記憶體管理瞭解詳細資訊)。

當物件即將被銷燬時,它將收到 dealloc 訊息。如果物件保留了任何資源,現在應該釋放它們。

擴充套件 NSObject

[編輯 | 編輯原始碼]

Cocoa/Objective-C 應用程式中的所有類都應該是 NSObject 的派生類。因此,在定義新類時,您應該遵循一些基本規則

  • NSObject 派生
  • 直接或從派生類派生
  • 定義初始化器和析構器
  • 呼叫基類初始化器和析構器

NSObject 派生

[編輯 | 編輯原始碼]

要將您的類建立為 NSObject 的子類,請按如下方式定義它(在介面定義檔案“MyClass.h”中)

#import <Foundation/NSObject.h>

@interface MyClass : NSObject
{
@private
  /* instance variable declarations */
  AnotherClass* myMember;
}
/* method declarations */
@end

定義初始化器和析構器

[編輯 | 編輯原始碼]

初始化器是初始化物件的方法。在 Cocoa 中,NSObject 的初始化器稱為 initNSObjectinit 方法不知道使用者定義的類,因此無法正確初始化它們的例項。因此,必須為您的類編寫一個初始化器方法。如果初始化不需要任何引數,則要定義的方法稱為 init(即,您應該覆蓋基類初始化器)。這使得可以使用從 NSObject 派生的 new 類方法建立您的類的例項

MyClass* myObj = [[MyClass alloc] init];   // allocate and initialize the object

上面的程式碼建立了一個新的 MyClass 例項。由於 MyClass 沒有名為 allocinit 的方法,因此訊息會自動傳送到其基類。

要覆蓋您的類的初始化器,可以選擇在介面檔案中定義它

/* In MyObject.h, in the method declarations part */
- (id) init;

並在.m 檔案中實現它

/* In MyObject.m */
@implementation MyObject
- (id) init
{
    /* first initialize the base class */
    self = [super init]; 
    /* then initialize the instance variables */
    myMember = [AnotherClass new];
    /* finally return the object */
    return self;
}
@end

如果初始化需要其他引數,您應該定義一個類似 initWithParam: 的初始化器,例如

- (id) initWithMember: (AnotherClass) member
{
    self = [super init];
    myMember = [[AnotherClass alloc] initWithValue: member];
    return self;
}

即使這樣,也建議定義一個“預設”初始化器,它使用合適的預設引數呼叫您的 initWithXXX 方法

- (id) init
{
    return [self initWithMember: someDefaultValue];
}

析構器是一個負責釋放物件持有的所有資源的方法。析構器在釋放物件之前被呼叫,從而確保一切被正確清理。在 Cocoa 中,析構器方法是 dealloc。每個持有任何資源的類都應該定義一個 dealloc 方法。例如

- (void) dealloc
{
   [myMember release];
   [super dealloc];
}

呼叫基類初始化器和析構器

[編輯 | 編輯原始碼]

當一個類從另一個類派生(例如,MyClassNSObject 派生)時,從它建立的例項不僅是派生類的例項,也是基類的例項。這稱為is-a 關係。派生類是基類的擴充套件:它可以做基類不能做的事情,但它可以做基類能做的一切。因此,派生類的物件總是包含基類物件包含的一切。如果 NSObject 包含一個保留計數成員變數,那麼 MyClass 物件也會包含它。因此,在初始化和銷燬派生物件時,需要初始化和銷燬派生物件的“基類部分”。

要初始化物件的基類部分,請編寫

self = [super init];

到您的類的初始化器的開頭。要銷燬物件的基類部分,請編寫

[super dealloc];

到您的類的析構器的結尾

更多資訊

[編輯 | 編輯原始碼]

有關 Cocoa 中 Objective-C 的更多資訊,請參閱

華夏公益教科書