Data Source 与Delegate 的差别?
我们现在可以来看看UITableView
与UITableViewController
是怎么运作的。UITableViewController
在loadView
中建立了一个UITableView
的instance,指定成是自己的view,同时将这个view的delegate与data source设定成自己。一个class可以根据需要,将delegate拆成好几个,以UITableView
来说,跟表格中有什么资料有关的,就放在data source中,其余的method放在delegate中。
我们在Mac OS X会用到的最庞大的UI元件,莫过于WebView
,虽然在iOS上UIWebView
被阉割到只剩下四个delegate method,但是Mac OS X上足足有五大类delegate method,网页页框的载入进度、个别图片档案的载入进度、下载档案的UI呈现、该不该开新视窗或是新分页、没有安装Java或是Flash要怎么呈现、用JavaScript跳出alert该怎么呈现…都是一堆delegate method。
假如先不管UITableView
怎么重复使用UITableViewCell
的机制(这个机制还顶复杂),我们要更新UITableView
的资料时,先指定data source物件后,要呼叫一次reloadData
。reloadData
可能是这样写的:
- (void)reloadData
{
NSInteger sections = 1;
if ([dataSource respondsToSelector:
@selector(numberOfSectionsInTableView:)]) {
sections = [dataSource numberOfSectionsInTableView:self];
}
for (NSInteger section = 0; section < sections; section++) {
NSInteger rows = [dataSource tableView:self
numberOfRowsInSection:section];
for (NSInteger row = 0; row < rows; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row
inSection:section];
UITableViewCell *cell = [dataSource tableView:self
cellForRowAtIndexPath:indexPath];
// Do something with the cell...
}
}
}
我们注意到几件事情:首先,因为numberOfSectionsInTableView:
被定义成是optional的delegate method,delegate不见得要实现,所以我们会用respondsToSelector:
检查是否有实现。我们可以在protocol的宣告中,指定某个delegate method是required或是optional,如果不特别指定的话,预设都是required。我们简单看一下UITableViewDataSource
就知道如何定义required与optional的delegate method。
@protocol UITableViewDataSource<NSObject>
@required
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath;
@optional
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
// ....
@end
另外,就是定义在data source的method,是在reloadData
中被呼叫,因此我们可以知道UITableView
的data source与delegate的最大差别:我们绝对不可以在data source定义的method中呼叫reloadData
,不然就会进入死循环!