從C#到Objective-C,按部就班學習蘋果開發(3)--分類(category)和協議Protocal的理解

本隨筆系列主要介紹從一個Windows平臺從事C#開發到Mac平臺蘋果開發的一系列感想和體驗歷程,本系列文章是在起步階段逐步積累的,但願帶給你們更好,更真實的轉換歷程體驗。本文繼續上一篇隨筆《從C#到Object C,按部就班學習蘋果開發(2)--Objective-C和C#的差別》,繼續對比介紹它們二者之間的差別,以便咱們從C#陣營過來的人員加深印象,深刻了解Objective-C語言的特性。本篇隨筆主要針對Objective-C裏面的分類(category)和協議Protocal概念的理解進行介紹。html

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

若是咱們使用過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的使用場景:設計

一、當你在定義類的時候,在某些狀況下(例如需求變動),你可能想要爲其中的某個或幾個類中添加方法。
二、一個類中包含了許多不一樣的方法須要實現,而這些方法須要不一樣團隊的成員實現
三、當你在使用基礎類庫中的類時,你可能但願這些類實現一些你須要的方法。
 
遇到以上這些需求,Category能夠幫助你解決問題。固然,使用Category也有些問題須要注意,
一、Category能夠訪問原始類的實例變量,但不能添加變量,若是想添加變量,能夠考慮經過繼承建立子類。
二、Category能夠重載原始類的方法,但不推薦這麼作,這麼作的後果是你不再能訪問原來的方法。若是確實要重載,正確的選擇是建立子類。
三、和普通接口有所區別的是,在分類的實現文件中能夠沒必要實現全部聲明的方法,只要你不去調用它。

還有一種成爲類擴展的功能,它是針對存在代碼的類的狀況,也就是你的類代碼和你擴展的源碼是同時編譯的狀況下。

類擴展的方法和上面的分類相似,他們不須要寫擴展分類的名稱,這個有點像匿名擴展分類的概念了,以下所示

@interface ClassName ()
 
@end

這個匿名的擴展分類,和普通的Category不一樣,它除了能夠方法外,還能夠添加屬性或者變量的。

 

二、協議Protocal

這個概念有很大程度上和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#是多個接口)的狀況。

相關文章
相關標籤/搜索