蘋果官方的解釋:html
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.java
其大意是:代理是一種簡單而強大的模式,委託方持有代理對象的引用,並對其發送消息,代理方接收消息並處理返回結果。其主要價值在於,能實現一個對象中實現多個對象的功能,相似「多繼承」。c++
代理模式是通用的設計模式,Cocoa框架中大量使用了這種模式來實現數據和UI的分離,如UITableView
、UIApplicationDelegate
等,其主要有三部分組成:git
直觀的關係圖以下(借樓): github
下面將重點闡述「協議」的概念及使用;objective-c
Protocol
協議相似java
中的接口或者c++
中的純虛函數,只提供接口不提供實現,Î不一樣於c++
中的純虛函數,其不存在類繼承關係,但遵循協議繼承。segmentfault
@protocol FSSubDelegate <NSObject, FSDelegate>
@required
//methodList or protertyList
@optional
//methodList or protertyList
@end
複製代碼
協議中存在兩個修飾符@required
和@optional
,默認爲@required
,修飾符指示遵循協議下的方法或者屬性是否必需要實現.設計模式
協議須要繼承「基協議」NSObject
(不一樣於NSObject
基類),其中規定了一些全部基類都須要實現的基本方法和屬性,好比isEqual:
、isKindOfClass
、respondsToSelector
等,內存管理的方法retain
、release
、autorelease
、retainCount
等,這樣就定義了一個相對統一的接口和 OC
對象均可以響應的方法。OC
對象是不支持多繼承的,但協議能夠多繼承。app
注意:協議中是能夠添加屬性,只是在代理模式中不多使用,但類別category是沒法添加屬性,除非使用關聯對象。框架
協議中經常使用的繼承自NSObject
基協議的方法以下:
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
- (BOOL)respondsToSelector:(SEL)aSelector;
複製代碼
因爲協議是「類無關」的,任何類均可以實現定義好的協議,所以能夠經過conformsToProtocol:
方法來判別某個類是否實現了特定協議;即便協議中指定了@required
,代理對象也能夠不遵循協議規定不實現協議必須實現的方法(只是編譯警告),能夠經過respondsToSelector
來判別代理對象是否實現了特定方法,避免運行期崩潰。
對於協議定義的位置,可根據使用狀況來決定,若是隻是使用在某個類中,可直接定義在類文件中;若多個類都是用同一個協議,可定義在統一的文件中。
以開放中常見的UITableView
爲例說明,通常的使用以下:
@protocol UITableViewDelegate <NSObject, UIScrollViewDelegate>
...
@end
@protocol UITableViewDataSource <NSObject>
...
@end
@interface UITableView
@property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
@end
@implementation UIViewController <UITableViewDelegate, UITableViewDataSource>
- (void) viewDidLoad {
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
#pragma mark -- UITableViewDelegate
//須要遵循實現的協議方法
#pragma mark -- UITableViewDataSource
////須要遵循實現的協議方法
@end
複製代碼
基於代理模式的關係圖解釋,其中協議爲UITableViewDelegate
及UITableViewDataSource
分別提出了
UITableVeiwCell
的顯示、編輯、選擇及其內容、索引、數目等需求;委託方爲UITableView
持有弱引用的代理對象delegate
,經過delegate
調用協議中的方法並傳遞參數;代理方UIViewController
須要實現協議中的方法來完成UITableView
中的需求,最終實現UITableView
控件的內容顯示、編輯、滑動、跳轉等動做。其中委託方中的代理屬性須要爲弱引用,避免與代理方循環引用而兩個對象沒法釋放。
經過上述通用案例說明:委託方能夠存在多個代理對象,一個代理對象也能夠有多個委託方(如數據源代理對象可經過分離對象實現,而不指定爲UIViewController
,以實現鬆耦合)。
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
...
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
struct objc_protocol_list {
struct objc_protocol_list * _Nullable next;
long count;
__unsafe_unretained Protocol * _Nullable list[1];
};
struct protocol_t : objc_object {
const char *mangledName;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
// Fields below this point are not always present on disk.
const char **_extendedMethodTypes;
const char *_demangledName;
property_list_t *_classProperties;
//省略一些封裝的便捷 get 方法
....
};
複製代碼
觀察類對象的結構可發現存在struct objc_protocol_list
類型的協議鏈表,而且協議結構體中存在屬性信息(也說明協議中可定義屬性),所以代理對象實現協議方法,即將協議方法添加至類對象中,可經過以下runtime
方法獲取協議方法: 具體的類結構圖信息以下圖所示(借樓):
method
來避免消息轉發)。
Cocoa Core Competencies -- Delegation