第23条:通过委托与数据源协议进行对象间通信
1. 委托模式
对象之间经常需要相互通信,在iOS中通信有委托和Block两种方式。委托模式(Delegate pattern)定义一套接口,某对象若想接受另一个对象的委托,则需遵从此接口,以便成为其“委托对象”(delegate)。而这“另一个对象”则可以给其委托对象回传一些信息,也可以在发生相关事件时通知委托对象。此模式可将数据与业务逻辑解耦。
2. 例子
Snip20160325_9.pngEOCNetworkFetcher类
/* EOCNetworkFetcher头文件 */
#import <Foundation/Foundation.h>
@class EOCNetworkFetcher;
// 委托协议
@protocol EOCNetworkFetcherDelegate
@optional
- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didReceiveData:(NSData*)data;
- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didFailWithError:(NSError*)error;
- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didUpdateProgressTo:(float)progress;
@end
@interface EOCNetworkFetcher : NSObject
@property(nonatomic ,weak) id<EOCNetworkFetcherDelegate> delegate; // 用来存放委托对象的属性
@end
/* EOCNetworkFetcher实现文件 */
#import "EOCNetworkFetcher.h"
@interface EOCNetworkFetcher (){
struct { // 含有位段的结构体,用来缓存“委托对象是否能响应相应协议方法”这一信息
unsigned int didReceiveData : 1;
unsigned int didFailWithError : 1;
unsigned int didUpdateProgressTo : 1;
}_delegateFlags;
}
@end
@implementation EOCNetworkFetcher
// 覆写delegate的setter方法
- (void)setDelegate:(id<EOCNetworkFetcherDelegate>)delegate
{
_delegate = delegate;
_delegateFlags.didReceiveData = [_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
_delegateFlags.didFailWithError = [_delegate respondsToSelector:@selector(networkFetcher:didFailWithError:)];
_delegateFlags.didUpdateProgressTo = [_delegate respondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)];
}
// 伪方法,从网络获取数据
- (void)dataFromNetwork
{
NSData *data = /* data obtained from network */;
if (_delegateFlags.didReceiveData) {
[_delegate networkFetcher:self didReceiveData:data];
}
}
@end
EOCDataModel类
/* EOCDataModel实现文件 */
#import "EOCDataModel.h"
#import "EOCNetworkFetcher.h"
@interface EOCDataModel () <EOCNetworkFetcherDelegate> // 遵守**协议
@end
@implementation EOCDataModel
#pragma mark - EOCNetworkFetcherDelegate
- (void)networkFetcher:(EOCNetworkFetcher *)fetcher didReceiveData:(NSData *)data
{
/* handle data */
}
- (void)networkFetcher:(EOCNetworkFetcher *)fetcher didFailWithError:(NSError *)error
{
/* handle error */
}
@end
3. 注意点
- delegate的属性要定义为weak。
- 如果在委托对象上调用委托协议的可选方法,那么必须提前使用类型信息查询方法判断这个委托对象能否响应相应选择子。但是,没必要频繁执行此操作。鉴于此,通常把“委托对象能否响应某个协议方法”这一信息缓存到含有位段的结构体中,以优化程序效率。
- delegate对象中的方法名总是应该准确描述当前发生的事件以及delegate对象为何要获知此事件。
- delegate里的方法也可以用于从获取委托对象中获取信息。
- 用协议定义一套接口,令某类经由该接口获取其所需的数据。委托模式的这一用法旨在向类提供数据,故而又称“数据源模式”(Data Source Pattern)。在此模式中,从数据源流向类,而在常规的委托模式中,信息则从类流向受委托者(delegate)。
要点
- 委托模式为对象提供了一套接口,使其可由此将相关事件告知其他对象。
- 将委托对象应该支持的接口定义成协议,在协议中把可能需要处理的事件定义成方法。
- 当某对象需要从另外一个对象中获取数据时,可以使用委托模式。这种情境下,该模式亦称“数据源模式”。
- 若有必要,可实现含有位段的结构体,将委托对象是否能响应相应协议方法这一信息缓存至其中。
网友评论