本隨筆系列主要介紹從一個Windows平臺從事C#開發到Mac平臺蘋果開發的一系列感想和體驗歷程,本系列文章是在起步階段逐步積累的,但願帶給你們更好,更真實的轉換歷程體驗。本文繼續上一篇隨筆《從C#到Object C,按部就班學習蘋果開發(2)--Objective-C和C#的差別》,繼續對比介紹它們二者之間的差別,以便咱們從C#陣營過來的人員加深印象,深刻了解Objective-C語言的特性。本篇隨筆主要針對Objective-C裏面的分類(category)和協議Protocal概念的理解進行介紹。html
若是咱們使用過C#,咱們都知道,C#裏面有一個叫作擴展函數的東西,能夠在不繼承已有類的狀況下,給存在的類增長一些本來沒有的接口函數,Objective-C的分類概念和這個很類似,甚至能夠說是同一類型的東西,雖然不知道他們誰先誰後出現,這個東西的引入,能使得編程方面更加豐富高效。編程
Objective-C提供了一種不同凡響的方式——Category,能夠動態的爲已經存在的類添加新的行爲。這樣能夠保證類的原始設計規模較小,功能增長時再逐步擴展。使用Category對類進行擴展時,不須要訪問其源代碼,也不須要建立子類。Category使用簡單的方式,實現了類的相關方法的模塊化,把不一樣的類方法分配到不一樣的分類文件中。不過Category並不能給類擴展出屬性,這點要注意,由於Object C不支持這樣的屬性擴展。框架
分類(Category)的定義語法以下所示。模塊化
@interface ClassName (CategoryName) @end
這裏好像它們還有一個約定俗成的習慣,將聲明文件和實現文件名稱統一採用「原類名+Category」的方式命名。因此OC的這種功能雖然和C#功能差很少,可是這點約定和C#不同,C#無論你放到哪裏都行,可是咱們仍是會應該尊重它的規則。函數
例如,咱們給XYZPerson類增長一個擴展方法的定義以下所示,這個定義的函數約定是放到文件"XYZPerson+XYZPersonNameDisplayAdditions.h"裏面。學習
#import "XYZPerson.h" @interface XYZPerson (XYZPersonNameDisplayAdditions) - (NSString *)testMethod; @end
那麼它的實現代碼以下所示,它的代碼約定是放到 "XYZPerson+XYZPersonNameDisplayAdditions.m"裏面。ui
#import "XYZPerson+XYZPersonNameDisplayAdditions.h" @implementation XYZPerson (XYZPersonNameDisplayAdditions) - (NSString *)testMethod { return [NSString stringWithFormat:@"%@, %@", self.lastName, self.firstName]; } @end
在C#裏面,擴展方法是命名空間相關的,一旦跳出了命名空間的範圍,這個擴展函數就不在起做用,而Objective-C的這個和類同樣,沒有命名空間的概念,所以在擴展的時候,須要當心謹慎一點,不然容易致使分類的接口和類自己發生衝突。基於這個緣由,因此蘋果建議也是給分類的接口增長一個前綴,命名則採用接口的一向規則,以下面代碼所示。this
@interface NSSortDescriptor (XYZAdditions) + (id)xyz_sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending; @end
這樣擴展方法名稱雖然長了一點,可是基本上確保和普通的接口方法不會發生衝突了。spa
Category的使用場景:設計
還有一種成爲類擴展的功能,它是針對存在代碼的類的狀況,也就是你的類代碼和你擴展的源碼是同時編譯的狀況下。
類擴展的方法和上面的分類相似,他們不須要寫擴展分類的名稱,這個有點像匿名擴展分類的概念了,以下所示
@interface ClassName () @end
這個匿名的擴展分類,和普通的Category不一樣,它除了能夠方法外,還能夠添加屬性或者變量的。
這個概念有很大程度上和C#的接口相似,可是它有所不一樣,它能夠可選的實現接口@optional,也有必選的實現接口@required,雖然Objective-C裏面已經有一個關鍵字 @interface,不過這個和Protocal仍是有不一樣的。
和C#的接口同樣,這種協議也能夠繼承自另一個Protocal,也就是他們能夠有繼承關係。
@protocol NewProtocal <Protocal> @end
因爲Objective-C開發的不少應用,如IOS的應用,他們在MVC的開發模型裏面,都大量使用了代理模式,這種Protocal很好的處理了這種關係。在iOS和OS X開發中,Apple採用了大量的代理模式來實現MVC中View和Controller的解耦。
例如UIView產生的全部事件,都是經過委託的方式交給Controller完成。根據約定,框架中後綴爲Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate等。
在C#裏面有不少如IClonable, IEnumerable這樣的接口,只要實現了,就能實現克隆和枚舉,在Objective-C裏面,這個就是可使用Protocal來替代了,若是某個協議繼承了NSObject,那麼這是表明在此聲明的協議,是NSObject協議的衍生協議(不是NSObject類),也就是說,這裏的語境理解NSObject是一個協議,若是是在@Interface裏面的繼承關係,那麼那個就是NSObject對象。有點意思哦。
下面是一個可選和必選的協議定義例子。
@protocol XYZPieChartViewDataSource - (NSUInteger)numberOfSegments; - (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex; @optional - (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex; - (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex; @required - (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex; @end
因爲協議有可選和必選,若是咱們想知道某個動態的對象是否具備某個接口函數,就是經過@selector操做符來進行判斷的。
NSString *thisSegmentTitle; if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) { thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index]; }
和C#的接口定義相似,Objective-C的一個類對象它能夠實現多的協議,以下例子是一個類的接口定義實現幾個協議的狀況。
@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol> ... @end
這樣就實現了MyClass對象只有一個基類對象,可是能夠實現多個協議(C#是多個接口)的狀況。