NSObject class和NSObject protocol的關係(抽象基類與協議)

NSTopGun發表於2013-10-04

【轉載請註明出處】

1、介面的實現

對於介面這一概念的支援,不同語言的實現形式不同。Java中,由於不支援多重繼承,因此提供了一個Interface關鍵詞。而在C++中,通常是通過定義抽象基類的方式來實現介面定義的。

Objective-C既不支援多重繼承,也沒有使用Interface關鍵詞作為介面的實現(Interface作為類的宣告來使用),而是通過抽象基類和協議(protocol)來共同實現介面的。

 

2、介面的意義

物件導向程式設計中一條重要的經驗法則是:對介面程式設計,而不是對實現程式設計。即一個物件想要呼叫另一個物件的方法,往往不會直接採取直接呼叫的形式。為降低耦合度考慮,通常會在呼叫者和被呼叫者中間增加一層抽象的(通常不會變動的)中間層,介面就是中間層的最通用的形式。

 

3、Objective-C中的介面與協議protocol

如前所述,Objective-C中使用協議protocol作為支援介面實現的關鍵詞。

如下類A的物件想要呼叫類B的物件的方法:

Class A中:

- (void)doSth:(B *)b

{

  [b doSth];

}

增加一個抽象的(通常不會變動的)中間層作為中介,如下:

定義一個protocol:

@protocol doSthDelegate

(void)doSth;

@end

 

Class A中:

- (void)doSth:(id<doSthDelegate>) delegate

{

  if (delegate)

  [delegate doSth];

}

 

4、Objective-C中的介面與抽象基類

協議protocol其實是足以支援介面的語法實現的,但對於需要頻繁呼叫的方法來說,未免不夠簡潔。如在NSObject協議中宣告的alloc、dealloc、retain、release和autoRelease等幾乎出現在iOS開發各個角落的方法,如果都需要

if (delegate && delegate respondsToSelector:@selector(func)

{
  [delegate func];

}

那就太過麻煩了。因此NSObject Class出現了。

在NSObject中對NSObject protocol中的方法都做了基本的實現,因而保證了處於NSObject派生鏈中的子類在呼叫NSObject protocol中的方法時的可靠性。寫法上也變得極為簡潔。

 

5、抽象基類和協議共存

如4中所述,抽象基類相比於協議,一方面提供了一些方法的基本實現,使得子類不需要重複實現,另一方面能夠保持語法的簡潔。因此,只使用協議而不使用抽象基類,是可行的,但極不方便。

而單獨使用抽象基類支援介面的語法,是基本上不可行的。如SDK中的UIView及其子類,由於Objective-C的單繼承限制,這些已經有基類的類,就不能使用介面了。當然,開發者自行定義的類,是可以完全依靠抽象基類進行組織的。

 

6、抽象基類和協議如何協作

經典範例就是標題中的NSObject class和NSObject protocol。

在Cocoa Touch中,並非所有的類都派生自NSObject,如NSProxy類(它本身是一個root class)。但是,對NSProxy和NSproxy的派生類的物件的記憶體控制,仍然採用alloc、dealloc、retain、release和autoRelease是很自然的想法。在不改變NSProxy基類的情況下,就只能通過協議來支援。

在NSObject協議中,宣告瞭retain、release和autoRelease方法(alloc和dealloc在NSProxy有定義),而NSProxy實現了NSObject協議(conform to protocol NSObject),因此可以做到

[proxyObj release];

這樣的呼叫。

 

7、總結

在Objective-C中,介面的支援主要由協議protocol來實現,抽象基類用於簡化語法、提供通用方法的基礎實現。

 

參考:

【1】Objective-C程式設計之道

【2】NSObject class and protocol

http://objectmix.com/c/177917-nsobject-class-protocol.html

【3】NSProxy Class Reference

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html

相關文章