什麼是協議 || 協議基本概念 || Protocol概述 || 協議的繼承機制

Hello 大家好,我是Stefan,今天給大家帶來的時iOS編程中非常重要的一個知識要點:協議

1.1 什麼是協議

1.1.1 協議基本概念

《倚天屠龍記》中,峨眉派的紀曉芙因爲愛上了明教光明右使楊逍,違反了峨眉派“不得與魔教人士往來”的條規,最終被滅絕師太一掌斃命,香消玉殞。可惜一位絕世佳人,卻因爲條條框框的門規協定而枉送了性命。

iOS編程中的協議其實也是如此,iOS裏面協議不是類,它是一種約定,約定了哪些條款一定要你實現,哪些條款你可以自己選擇是不是要實現。而一定要實現的協定就像是峨眉派的條規啦,如果你想學紀曉芙,偷懶不去實現一些協議裏的必須實現的條款,那下場就和她一樣悲情了。但是它當然比迂腐固化的峨眉嚴規要自由許多,畢竟iOS編程是現代的產物,也就是因爲iOS中的協議提供了可選的條款,這樣你可以有很大的自由度,比如像“不得與魔教人士往來”這樣霸道的條款你可以寫到可選條款裏,這樣你不想遵守的時候就不遵守,反正它不是必須要實現的條款;這就是iOS的協議。

好了,廢話說了挺多,我們來看看iOS裏面到底如何來使用協議。

協議聲明瞭其它類可以調用的編程接口,這有點類似與java裏的接口,它使得類直接的通信變的簡單明瞭,下圖清晰的反應了協議與類之間的概念:
這裏寫圖片描述

圖1 Protocol概述

上圖中我們可以看到,協議(Protocol)將兩個繼承關係很遠的類聯繫起來。

一個普通的協議定義如下:

@protocol ProtocolName

// 這裏聲明一些方法

@end

我們再來看一個餅狀圖的示例:
這裏寫圖片描述

餅狀圖

   如圖,餅狀圖一般用來顯示數據,但是我們如果針對每一個有不同數據的餅狀圖都寫一個類,那工作量就太大了。一種方法是可以通過餅狀圖的屬性來自定義,當然,iOS裏給我們提供了另一種較爲快捷的方法,那就是用協議。

   協議裏面提供了可以提供一系列方法來供我們自定義餅狀圖,我們稱這些協議爲數據源協議,如下是上面提到的餅狀圖可能的數據源協議:

@protocol XYZPieChartViewDataSource // 協議名稱

  • (NSUInteger)numberOfSegments; // 餅狀圖的段數

  • (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex; // 特定段

所佔的百分比

@optional // 可選擇性實現的方法

  • (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex; // 特定段

的標題

@end

   協議已經定義了,那麼如何來通過協議自定義我們餅狀圖視圖呢?我們需要在餅狀圖視圖的頭文件中加入一個屬性,通過這個屬性來與數據源建立聯繫,由於數據源可以是任何的類(只要這個類遵守相關數據源協議),所以屬性的類型應該是id,後面還可以指定具體的協議名稱,代碼如下:

@interface XYZPieChartView : UIView// 餅狀視圖,繼承自 UIView

@property (weak) id dataSource; // 數據源屬性

的類型是 id , 其中 XYZPieChartViewDataSource 標定

了這個數據源遵守的協議

@end

注意:數據源屬性和代理屬性一般需要使用 weak 來標示屬性,原因在於避免循環引用。

1.1.2協議的方法

協議默認聲明在其中的方法爲必須實現的方法。也就是說只要遵守了這個協議,那麼這些方法必須要去實現。

   但是前面我們也提到了,iOS畢竟是先進社會的產物,它更加的人性化,因此,它還提供了可選的方法,我們可以在只有我們需要的時候纔去實現它,這樣靈活性就很高了。

   例如,前面的餅狀圖示例中,我們如果實現了titleForSegmentAtIndex方法,那麼將會顯示標題,反之則沒有,它就是一個可選的方法。

   通過@ optional 標誌我們可以標識可選方法,代碼如下:

@protocol XYZPieChartViewDataSource

  • (NSUInteger)numberOfSegments;

  • (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;

@optional // 可選方法標誌

  • (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex; // 可選方法

@end

@optional標誌下所有的方法都應是可選的方法,除非下面又有其它的標誌,比如如果下面出現了@required標誌的話,那麼從@required開始再下面的方法就不是可選的方法了,而是必須實現的方法。代碼示例如下:

@protocol XYZPieChartViewDataSource

  • (NSUInteger)numberOfSegments;

  • (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;

@optional // 可選的方法標誌,直到 @required 標誌,都是可選的方法

  • (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;

  • (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex;

@required // 必須的方法標誌,以下都是必須的方法

  • (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;

@end

上面的示例中定義一個有着三個必須實現的方法和兩個可選擇實現的方法的協議。

1.1.3 避免不遵守協議的風險

   前面提到了紀曉芙因爲沒有遵守峨眉派的門規,或者說協定而命喪滅絕之手,假使她能提前知道這個門規必須遵守,或者有人提醒她不遵守的嚴重後果,她可能就會爲了楊不悔而遠走他鄉了。當然這都是後話,不過強大先進的iOS考慮到了這點,爲了避免悲劇的發生。

   當我們需要調用協議裏面的可選方法時,我們不知道遵循協議的類是不是已經實現了這些方法,這時我們可以通過respondsToSelector 方法來判斷是否實現了某個方法,代碼示例如下:

NSString *thisSegmentTitle; // 段標題

if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) { // 判斷是否存在

titleForSegmentAtIndex 方法

thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index]; // 調用方法

}

1.1.4 協議的繼承機制

   就像其它Objective-C類可以繼承一樣,協議也有類似的機制,我們可以使得一個協議遵循另一個協議。

   如果一個協議遵循另一個協議,類似與繼承機制,你就需要在協議中提供遵循的協議的方法,一般的,我們在iOS裏寫協議都回遵循NSObject協議。不過由於一般我們都是使用NSObject的子類,所以我們不需要提供NSObject協議方法的實現,對於遵循協議的形式,示例如下:

@protocol MyProtocol

@end

在上例中,任何遵循了MyProtocol的協議也會自動的遵循NSObject裏面聲明的方法。

1.1.5 如何遵循協議

爲了表明一個類遵循相關的協議,我們使用尖括號來包含協議,示例代碼如下:

@interface MyClass : NSObject

@end

一個類的實例如果遵循了相應的協議的話,那它就不僅僅是實現它本身在頭文件裏聲明的方法了,他還要實現協議裏聲明的方法,當然,他不需要在自己的頭文件裏再次聲明,只需要實現就可以了。

   當然,有時候我們覺得一個協議太少了,這個時候是不是會考慮用多個協議呢?iOS裏面我們可以通過逗號吧多個協議隔開,來實現同時遵循多個協議,示例代碼如下:

@interface MyClass : NSObject

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