從C#到Objective-C,循序漸進(jìn)學(xué)習(xí)蘋果開發(fā)(3)--分類(category)和協(xié)議Protocal的理解

本隨筆系列主要介紹從一個Windows平臺從事C#開發(fā)到Mac平臺蘋果開發(fā)的一系列感想和體驗歷程,本系列文章是在起步階段逐步積累的,希望帶給大家更好,更真實(shí)的轉(zhuǎn)換歷程體驗。本文繼續(xù)上一篇隨筆《從C#到Object C,循序漸進(jìn)學(xué)習(xí)蘋果開發(fā)(2)--Objective-C和C#的差異》,繼續(xù)對比介紹它們兩者之間的差異,以便我們從C#陣營過來的人員加深印象,深入了解Objective-C語言的特性。本篇隨筆主要針對Objective-C里面的分類(category)和協(xié)議Protocal概念的理解進(jìn)行介紹。

1、分類(category)概念和使用

如果我們使用過C#,我們都知道,C#里面有一個叫做擴(kuò)展函數(shù)的東西,可以在不繼承已有類的情況下,給存在的類增加一些原本沒有的接口函數(shù),Objective-C的分類概念和這個很相似,甚至可以說是同一類型的東西,雖然不知道他們誰先誰后出現(xiàn),這個東西的引入,能使得編程方面更加豐富高效。
Objective-C提供了一種與眾不同的方式——Category,可以動態(tài)的為已經(jīng)存在的類添加新的行為。這樣可以保證類的原始設(shè)計規(guī)模較小,功能增加時再逐步擴(kuò)展。使用Category對類進(jìn)行擴(kuò)展時,不需要訪問其源代碼,也不需要創(chuàng)建子類。Category使用簡單的方式,實(shí)現(xiàn)了類的相關(guān)方法的模塊化,把不同的類方法分配到不同的分類文件中。不過Category并不能給類擴(kuò)展出屬性,這點(diǎn)要注意,因為Object C不支持這樣的屬性擴(kuò)展。
分類(Category)的定義語法如下所示。

@interface ClassName (CategoryName)
 
@end

這里好像它們還有一個約定俗成的習(xí)慣,將聲明文件和實(shí)現(xiàn)文件名稱統(tǒng)一采用“原類名+Category”的方式命名。所以O(shè)C的這種功能雖然和C#功能差不多,但是這點(diǎn)約定和C#不一樣,C#不管你放到哪里都行,但是我們還是會應(yīng)該尊重它的規(guī)則。

例如,我們給XYZPerson類增加一個擴(kuò)展方法的定義如下所示,這個定義的函數(shù)約定是放到文件"XYZPerson+XYZPersonNameDisplayAdditions.h"里面。

#import "XYZPerson.h"
 
@interface XYZPerson (XYZPersonNameDisplayAdditions)
- (NSString *)testMethod;
@end

那么它的實(shí)現(xiàn)代碼如下所示,它的代碼約定是放到 "XYZPerson+XYZPersonNameDisplayAdditions.m"里面。

#import "XYZPerson+XYZPersonNameDisplayAdditions.h"
 
@implementation XYZPerson (XYZPersonNameDisplayAdditions)
- (NSString *)testMethod {
    return [NSString stringWithFormat:@"%@, %@", self.lastName, self.firstName];
}
@end

在C#里面,擴(kuò)展方法是命名空間相關(guān)的,一旦跳出了命名空間的范圍,這個擴(kuò)展函數(shù)就不在起作用,而Objective-C的這個和類一樣,沒有命名空間的概念,因此在擴(kuò)展的時候,需要小心謹(jǐn)慎一點(diǎn),否則容易導(dǎo)致分類的接口和類本身發(fā)生沖突。基于這個原因,所以蘋果建議也是給分類的接口增加一個前綴,命名則采用接口的一貫規(guī)則,如下面代碼所示。

@interface NSSortDescriptor (XYZAdditions)
+ (id)xyz_sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending;
@end

這樣擴(kuò)展方法名稱雖然長了一點(diǎn),但是基本上確保和普通的接口方法不會發(fā)生沖突了。
Category的使用場景:
1、當(dāng)你在定義類的時候,在某些情況下(例如需求變更),你可能想要為其中的某個或幾個類中添加方法。
2、一個類中包含了許多不同的方法需要實(shí)現(xiàn),而這些方法需要不同團(tuán)隊的成員實(shí)現(xiàn)
3、當(dāng)你在使用基礎(chǔ)類庫中的類時,你可能希望這些類實(shí)現(xiàn)一些你需要的方法。

遇到以上這些需求,Category可以幫助你解決問題。當(dāng)然,使用Category也有些問題需要注意,
1、Category可以訪問原始類的實(shí)例變量,但不能添加變量,如果想添加變量,可以考慮通過繼承創(chuàng)建子類。
2、Category可以重載原始類的方法,但不推薦這么做,這么做的后果是你再也不能訪問原來的方法。如果確實(shí)要重載,正確的選擇是創(chuàng)建子類。
3、和普通接口有所區(qū)別的是,在分類的實(shí)現(xiàn)文件中可以不必實(shí)現(xiàn)所有聲明的方法,只要你不去調(diào)用它。
還有一種成為類擴(kuò)展的功能,它是針對存在代碼的類的情況,也就是你的類代碼和你擴(kuò)展的源碼是同時編譯的情況下。
類擴(kuò)展的方法和上面的分類類似,他們不需要寫擴(kuò)展分類的名稱,這個有點(diǎn)像匿名擴(kuò)展分類的概念了,如下所示

@interface ClassName ()
 
@end

這個匿名的擴(kuò)展分類,和普通的Category不同,它除了可以方法外,還可以添加屬性或者變量的。

2、協(xié)議Protocal

這個概念有很大程度上和C#的接口類似,但是它有所不同,它可以可選的實(shí)現(xiàn)接口@optional,也有必選的實(shí)現(xiàn)接口@required,雖然Objective-C里面已經(jīng)有一個關(guān)鍵字 @interface,不過這個和Protocal還是有不同的。
和C#的接口一樣,這種協(xié)議也可以繼承自另外一個Protocal,也就是他們可以有繼承關(guān)系。

@protocol NewProtocal <Protocal>
@end

由于Objective-C開發(fā)的很多應(yīng)用,如IOS的應(yīng)用,他們在MVC的開發(fā)模型里面,都大量使用了代理模式,這種Protocal很好的處理了這種關(guān)系。在iOS和OS X開發(fā)中,Apple采用了大量的代理模式來實(shí)現(xiàn)MVC中View和Controller的解耦。
例如UIView產(chǎn)生的所有事件,都是通過委托的方式交給Controller完成。根據(jù)約定,框架中后綴為Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate等。
在C#里面有很多如IClonable, IEnumerable這樣的接口,只要實(shí)現(xiàn)了,就能實(shí)現(xiàn)克隆和枚舉,在Objective-C里面,這個就是可以使用Protocal來替代了,如果某個協(xié)議繼承了NSObject,那么這是代表在此聲明的協(xié)議,是NSObject協(xié)議的衍生協(xié)議(不是NSObject類),也就是說,這里的語境理解NSObject是一個協(xié)議,如果是在@Interface里面的繼承關(guān)系,那么那個就是NSObject對象。有點(diǎn)意思哦。
下面是一個可選和必選的協(xié)議定義例子。

@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
- (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex;
@required
- (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;
@end

由于協(xié)議有可選和必選,如果我們想知道某個動態(tài)的對象是否具有某個接口函數(shù),就是通過@selector操作符來進(jìn)行判斷的。

NSString *thisSegmentTitle;
    if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
        thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
    }

和C#的接口定義類似,Objective-C的一個類對象它可以實(shí)現(xiàn)多的協(xié)議,如下例子是一個類的接口定義實(shí)現(xiàn)幾個協(xié)議的情況。

@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol>
...
@end

這樣就實(shí)現(xiàn)了MyClass對象只有一個基類對象,但是可以實(shí)現(xiàn)多個協(xié)議(C#是多個接口)的情況。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內(nèi)容