2014-04-01 34 views
3

我正在通過蘋果提供的Programming with Objective-C文件。一個符合協議的身份證明與一個協議的身份證明ID

我想了解以下段落,但到目前爲止,無法做到這一點。

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

@interface XYZPieCharView : UIView 
@property (weak) id <XYZPieChartViewDataSource> dataSource; 
// some additional stuff 
@end 

如果您嘗試調用respondsToSelector:方法上,因爲它的上面定義符合協議的ID ,你會得到一個 編譯器錯誤有沒有它的已知實例方法。一旦你通過一個協議對一個id進行了限定,所有的靜態類型檢查都會返回; 如果您嘗試調用指定協議中未定義的任何方法 ,則會出現錯誤。避免編譯器錯誤的一種方法是將 設置爲使用NSObject協議的自定義協議。

我對「符合協議」和「使用協議限定某個對象」之間的區別感到困惑。如果我們發送一個id - 符合協議 - respondsToSelector消息,爲什麼編譯器會產生錯誤?

+0

到目前爲止我已經實現了很多很多的協議數據源代表,但我無法確切地說出句子想要解釋的內容。但是,我使用的協議沒有問題。以我個人的拙見來看,我認爲你要在實際情況下實現它,並且看看它是如何工作的,並且感覺當你需要一個協議是最快的學習方式時。 – John

回答

5

何必編譯器產生一個錯誤,如果我們發送的ID - 這符合協議 - 將respondsToSelector消息

是的,這是一個非常奇怪的事情。現在,在ARC下,如果一個聲明爲id <XYZPieChartViewDataSource>的對象被髮送respondsToSelector:方法,class方法或任何其他熟悉的基本NSObject實例方法,編譯器將會拋出一個錯誤!試試看看。

這似乎很奇怪,因爲id應該允許發送任何(已知)消息給它。但是,id <XYZPieChartViewDataSource>被認爲是完全特定的類型;編譯器將允許只有消息是XYZPieChartViewDataSource協議的一部分。一個現代化的解決方案是:不使用

id <XYZPieChartViewDataSource> 

相反,使用

NSObject<XYZPieChartViewDataSource>* 

這將導致包括所有的NSObject的美味善良(至於編譯器而言)在此對象,包括對respondsToSelector:class以及類似的事情做出迴應的能力。

這裏有一個段落,我插在我的書,討論就此問題:

奇怪的是,編譯器將類型爲id<SomeProtocol>非常不同的對象從它怎樣對待類型爲id對象,只允許在SomeProtocol中定義的方法被髮送到該對象。例如,假設MyClass被定義爲delegate屬性類型爲id<MyProtocol>。然後,如果obj是MyClass實例,則不能說[obj.delegate class];編譯器抱怨class不是已知的實例方法!這是因爲obj.delegate被鍵入爲id<MyProtocol>,因此其只有已知實例方法是doSomething:,該方法由MyProtocol定義。我們可以通過將obj.delegate轉換爲id來解決此問題;當MyClass的定義取決於我們時,更優雅的解決方案是將delegate屬性聲明爲NSObject<MyProtocol>*而不是id<MyProtocol>

+0

讓你的協議延伸'< NSObject >'意味着你在運行時得到的對象可能是'NSProxy',並且指定協議比指定類類型更具限制性(通常被認爲是好的做法)。那麼將協議指定爲「NSObject」的優點是什麼?個人喜好或我錯過了什麼? – Wain

+0

@Wain讓協議指定它符合''協議也可以。我從來沒有使用過NSProxy,所以實際上這種區別從來沒有出現過。另外,我從Apple Park的Greg Parker那裏得到了'NSObject <...> *'的想法,我傾向於隨他說的去做! :)我已經編輯了我的答案了一下。 – matt

+0

當然這根本不是「好奇」的,儘管第一眼看起來可能有點令人困惑。聲明一個變量是一個類的類型是斷言參考對象提供了類的方法等,它不會聲明其他任何東西。聲明一個變量是一個協議類型應該是一個直接的並行(在Java中也是如此)。這裏沒什麼好奇的。唯一的問題是語法。由於協議在語法類的後面出現在<>括號內,所以「使用協議」的意思是「id」,「任何事物和協議」都是冗餘規格。 – CRD

4

符合協議

這是當你@interface定義爲類指定的類實現(或符合)的協議。這是編譯器的信息,以驗證該類確實實現了所需的方法。

@interface MyClass <MyProtocol> 

資格一些物體協議

這是添加額外的信息,指針類型,通常是id,告訴對象它引用將落實規定的方法編譯協議(所以它們是有效的被稱爲)。與此相反的是,協議中未定義的任何方法都無法被調用,如果您嘗試,您會收到警告。

id <MyProtocol> myObject = ...;