考虑下面这种情况,在一个UIViewController的view中添加一个UITableView作为subview,为了填充数据到这个UITableView,告诉它有多少个section,每个section有多少行,每行显示什么内容,一般把UITableView的dataSource属性设置为self,即UIViewController,意思是这个UIViewController会提供数据。然后使UIViewController服从UITableViewDataSource协议,并至少实现下面三种协议方法:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
这三个方法在UITableView加载数据的时候,会被调用。当UITableView想要知道自己要显示多少个section的时候,就会调用dataSource中的numberOfSectionsInTableView:方法;继而想要知道每个section有多少行需要显示的时候,会调用tableView:numberOfRowsInSection:方法;最后,想要得到每行显示的数据是什么,就去调用tableView:cellForRowAtIndexPath:方法。
其实这里就使用了delegate开发模式。即本来应该自己做的事,由于某种原因自己做不到,需要别人帮助来完成。假设Boss想知道明天要开什么会,就会去问Secretary,Secretary扮演的角色是老板的delegate,所以Secretary就会告诉老板明天的事务。放在UITableView中,就是一个UITableView想要知道显示的数据是什么,但是自身又不能提供,就需要自己的dataSource来提供,当把dataSource设置为一个UIViewController的时候,UITableView就会去询问这个UIViewController:“Hey! Tell me how many sections I should have!”。
Delegate一般与协议一起使用,使用协议就是为了明确告诉自己的委托需要帮我做哪些事。就好比上面的UITableView的dataSource需要服从UITableViewDataSource协议一样。
下面使用一个例子来介绍Delegate的使用:有一个TextViewController,需要显示一个字符串,这个字符串需要从服务器获取,TextViewController把获取工作交给DataFetchingModel类(继承自NSObject),下载数据的时候,需要知道数据地址(NSURL)是什么,等下载完毕,需要告知TextViewController我下载完了,你可以拿去显示了。
首先看DataFetchingModel类的接口文件:
@class DataFetchingModel;
@protocol DataFetchingModelDelegate
- (NSURL *)URLForDataFetchingModel:(DataFetchingModel *)model;
- (void)DataFetchingModelDidFinishingFetchingData:(NSString *)data;
@end
@interface DataFetchingModel : NSObject
- (void)fetchingData;
@property (weak, nonatomic) id delegate;
@end
第3-8行声明了一个协议,10-15行声明了类的接口。在声明delegate的时候,需要使用弱引用,类型为id,因为delegate可以为任何对象。这里可以不使用delegate作为属性名,属性名是任意的,但为了方便和易读,一般使用delegate。接口还提供了一个fetchingData方法,用于开始获取数据。
下面看DataFetchingModel的实现部分:
@implementation DataFetchingModel
- (void)fetchingData
{
NSURL *url = [_delegate URLForDataFetchingModel:self];
// network action
[_delegate DataFetchingModelDidFinishingFetchingData:@"Fake String"];
}
@end
fetchingData方法被调用的时候,首先会询问delegate下载数据的URL是什么,然后去下载,等下载完毕,调用DataFetchingModelDidFinishingFetchingData方法,告知delegate我下载完了,你可以使用数据了。
DataFetchingModel部分就是这样,继续看一下TextViewController的代码:
@interface TextViewController ()
@property (strong, nonatomic) DataFetchingModel *dataModel;
@end
@implementation TextViewController
- (DataFetchingModel *)dataModel
{
if (!_dataModel) {
_dataModel = [DataFetchingModel new];
_dataModel.delegate = self; // set delegate as self
}
return _dataModel;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.dataModel fetchingData]; // start downloading data
}
#pragma mark - DataFetchingModelDelegate
- (NSURL *)URLForDataFetchingModel:(DataFetchingModel *)model
{
return [NSURL URLWithString:@"http://blog.kweima.com/demo"];
}
- (void)DataFetchingModelDidFinishingFetchingData:(NSString *)data
{
NSLog(@"%@", data);
}
@end
首先看第1行,使用了扩展,并且服从DataFetchingModelDelegate协议。第27-37行为协议方法的实现。第三行声明了一个DataFetchingModel实例,初始化代码在9-16行,初始化之后,把dataModel的delegate设置为self(TextViewController)。在viewDidLoad方法中,调用dataModel的fetchingData方法开始下载数据。
fetchingData方法开始执行,执行开始后,会询问delegate下载地址是什么,此时调用TextViewController(delegate)的URLForDataFetchingModel:方法,会得到一个NSURL实例。等待下载完毕,想通知TextViewController(delegate)我下载完了,这时就会调用DataFetchingModelDidFinishingFetchingData:方法,作为演示,代码中仅仅输出了这个字符串而已。
通过这个例子,介绍了Delegate的使用方法。Delegate的作用主要分为两个,一个是索要数据,一个是反馈。例子中索要数据和反馈都使用一个delegate来实现了,而UITableView使用了两个,一个是dataSource,一个是delegate,dataSource负责提供数据,delegate负责响应操作。
希望对Delegate不理解的朋友有所帮助。