Objective-C——Message(消息)、Category(分類) 、Protocol(協議) 總結

Ojbective-C的語法設計主要基於Smalltalk,除了提供傳統的面向對象編程特性之外,還增加了很多類似動態語言Ruby、Python才具有的特性,例如動態類型、動態加載、動態綁定等等,同時強化了消息傳遞機制和表意(Intention Revealing Interface)接口的概念。

 

—消息—

消息傳遞模型(Message Passing)是Objective-C語言的核心機制。在Objective-C中,沒有方法調用這種說法,只有消息傳遞。在C++或Java中調用某個類的方法,在Objective-C中是給該類發送一個消息。在C++或Java裏,類與類的行爲方法之間的關係非常緊密,一個方法必定屬於一個類,且於編譯時就已經綁定在一起,所以你不可能調用一個類裏沒有的方法。而在Objective-C中就比較簡單了,類和消息之間是鬆耦合的,方法調用只是向某個類發送一個消息,該類可以在運行時再確定怎麼處理接受到的消息。也就是說,一個類不保證一定會響應接收到的消息,如果收到了一個無法處理的消息,那麼程序就是簡單報一個錯。甚至你可以向一個值爲nil的空對象發送消息,系統都不會出錯或宕掉。這種設計本身也比較符合軟件的隱喻。

 

在表意接口(Intention Revealing Interface)方面,Objective-C也是設計的比較出色的語言。面嚮對象語言的特性之一就是通過API把實現封裝起來,爲上層建築提供服務。但是需要注意的一點就是,你封裝的API最好能夠讓調用者看到接口描述就知道怎麼使用。如果爲了使用一個API必須要去研究它的實現,那麼就失去了封裝的意義。Objective-C通過顯式的API描述,讓開發者不自覺的寫出滿足表意接口的API,比如下圖中的API描述。

下面我們來說說多態和繼承。

 與Java一樣,Objective-C一樣不支持多重繼承,但是通過類別(Category)和協議(Protocol)可以很好的實現代碼複用和擴展。

 

—Category

首先我們來談談Category

 

Objective-C提供了一種與衆不同的方式——Category,可以動態的爲已經存在的類添加新的行爲。這樣可以保證類的原始設計規模較小,功能增加時再逐步擴展。使用Category對類進行擴展時,不需要訪問其源代碼,也不需要創建子類。Category使用簡單的方式,實現了類的相關方法的模塊化,把不同的類方法分配到不同的分類文件中。

 

實現起來很簡單,我們舉例說明。

SomeClass.h
@interface SomeClass : NSObject{
}
-(void) print;
@end 


這是類SomeClass的聲明文件,其中包含一個實例方法print。如果我們想在不修改原始類、不增加子類的情況下,爲該類增加一個hello的方法,只需要簡單的定義兩個文件SomeClass+Hello.h和SomeClass+Hello.m,在聲明文件和實現文件中用“()”把Category的名稱括起來即可。聲明文件代碼如下:

#import "SomeClass.h"
 
@interface SomeClass (Hello)
-(void)hello;
@end

實現文件代碼如下

#import "SomeClass+Hello.h"
@implementation SomeClass (Hello)
-(void)hello{
    NSLog (@"name:%@ ", @"Jacky");
}
@end 

其中Hello是Category的名稱,如果你用XCode創建Category,那麼需要填寫的內容包括名稱和要擴展的類的名稱。這裏還有一個約定成俗的習慣,將聲明文件和實現文件名稱統一採用“原類名+Category”的方式命名。

調用也非常簡單,毫無壓力,如下:

首先引入Category的聲明文件,然後正常調用即可。

#import "SomeClass+Hello.h"
 
SomeClass * sc =[[SomeClass alloc] init];
[sc hello] 

執行結果是:

name:Jacky 

 

Category的使用場景:

1、當你在定義類的時候,在某些情況下(例如需求變更),你可能想要爲其中的某個或幾個類中添加方法。

2、一個類中包含了許多不同的方法需要實現,而這些方法需要不同團隊的成員實現

3、當你在使用基礎類庫中的類時,你可能希望這些類實現一些你需要的方法。

 

遇到以上這些需求,Category可以幫助你解決問題。當然,使用Category也有些問題需要注意,

1、Category可以訪問原始類的實例變量,但不能添加變量,如果想添加變量,可以考慮通過繼承創建子類。

2、Category可以重載原始類的方法,但不推薦這麼做,這麼做的後果是你再也不能訪問原來的方法。如果確實要重載,正確的選擇是創建子類。

3、和普通接口有所區別的是,在分類的實現文件中可以不必實現所有聲明的方法,只要你不去調用它。

 

用好Category可以充分利用Objective-C的動態特性,編寫出靈活簡潔的代碼。

 

—Protocol— 

下面我們再來看Protocol

Protocol,簡單來說就是一系列不屬於任何類的方法列表,其中聲明的方法可以被任何類實現。這種模式一般稱爲代理(delegation)模式。你通過Protocol定義各種行爲,在不同的場景採用不同的實現方式。在iOS和OS X開發中,Apple採用了大量的代理模式來實現MVC中View和Controller的解耦。

 

定義Protocol很簡單,在聲明文件(h文件)中通過關鍵字@protocol定義,然後給出Protocol的名稱,方法列表,然後用@end表示Protocol結束。在@end指令結束之前定義的方法,都屬於這個Protocol。例如:

@protocol ProcessDataDelegate <NSObject>
@required
- (void) processSuccessful: (BOOL)success;

@optional
- (id) submitOrder: (NSNumber *) orderid;
@end

以上代碼可以單獨放在一個h文件中,也可以寫在相關類的h文件中,可以視具體情況而定。該Protocol包含兩個方法,processSuccessful和submitOrder。這裏還有兩個關鍵字,@required和@optional,表示如果要實現這個協議,那麼processSuccessful方法是必須要實現的,submitOrder則是可選的,這兩個註解關鍵字是在Objective-C 2.0之後加入的語法特性。如果不註明,那麼方法默認是@required的,必須實現。

 

那麼如何實現這個Protocol呢,很簡單,創建一個普通的Objective-C類,取名爲TestAppDelegate,這時會生成一個h文件和m文件。在h文件中引入包含Protocol的h文件,之後聲明採用這個Protocol即可,如下:

@interface TestAppDelegate : NSObject<ProcessDataDelegate>;

@end

用尖括號(<...>)括起來的ProcessDataDelegate就是我們創建的Protocol。如果要採用多個Protocol,可以在尖括號內引入多個Protocol名稱,並用逗號隔開即可。例如<ProcessDataDelegate,xxxDelegate>

 

m文件如下:

@implementation TestAppDelegate

- (void) processSuccessful: (BOOL)success{
    if (success) {
        NSLog(@"成功");
    }else {
        NSLog(@"失敗");
    }
}

@end 

由於submitOrder方法是可選的,所以我們可以只實現processSuccessful。

 

Protocol一般使用在哪些場景呢?Objective-C裏的Protocol和Java語言中的接口很類似,如果一些類之間沒有繼承關係,但是又具備某些相同的行爲,則可以使用Protocol來描述它們的關係。不同的類,可以遵守同一個Protocol,在不同的場景下注入不同的實例,實現不同的功能。其中最常用的就是委託代理模式,Cocoa框架中大量採用了這種模式實現數據和UI的分離。例如UIView產生的所有事件,都是通過委託的方式交給Controller完成。根據約定,框架中後綴爲Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate等,使用時大家可以留意一下,體會其用法。

 

使用Protocol時還需要注意的是:

1、Protocol本身是可以繼承的,比如:

@protocol A
     -(void)methodA;
@end
@protocol B <A>
     -(void)methodB;
@end

如果你要實現B,那麼methodA和methodB都需要實現。 

2、Protocol是類無關的,任何類都可以實現定義好的Protocol。如果我們想知道某個類是否實現了某個Protocol,還可以使用conformsToProtocol進行判斷,如下:

[obj conformsToProtocol:@protocol(ProcessDataDelegate)] 

好吧,具體的語言特性這次就介紹這麼多。從某種意義上來說,Objective-C是一門古老的語言,發明於1980年。1988年,喬布斯的Next公司獲得了Objective-C語言的授權,並開發出了Objective-C的語言庫和NEXTSTEP的開發環境。NextStep是以Mach和BSD爲基礎,Objective-C是其語言和運行庫,後來的事大家都清楚,蘋果買了Next,喬布斯迴歸蘋果,開始神奇的蘋果振興之路,NextStep成了Max OS X的基礎。以後發展越來越好,Objctive-C成了Apple的當家語言,現在基本上是Apple在維護Objctive-C的發展。

 

在蘋果的AppStore推出之前,Objective-C一直相對小衆,但是其優秀的語言特性似乎一直在爲後面的爆發積蓄力量,當蘋果平臺級的應用出現之後,Objective-C開始大放異彩,靜態語言的效率和動態語言的特性得到衆多程序員的喜愛,目前它已經以火箭般的速度躥升TIOBE語言排行版第四位。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章