在《精通iOS开发》一书中看到的技巧。假设BIDTaskListController是一个列表,点击列表上的一项将会导航到BIDTaskDetailController,在BIDTaskDetailController当中修改值并保存后,将把修改后的值回传给BIDTaskListController并更新局部视图。
在BIDTaskListController类中有如下方法:
1 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 2 UIViewController *destination = segue.destinationViewController; 3 if ([destination respondsToSelector:@selector(setDelegate:)]) { 4 [destination setValue:self forKey:@"delegate"]; 5 } 6 if ([destination respondsToSelector:@selector(setSelection:)]) { 7 // prepare selection info 8 NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; 9 id object = self.tasks[indexPath.row]; 10 NSDictionary *selection = @{@"indexPath" : indexPath, 11 @"object" : object}; 12 [destination setValue:selection forKey:@"selection"]; 13 } 14 }
红字部分通过segue拿到了目标控制器,并且通过KVC的方式将自身设置为了目标的代理。
在BIDTaskDetailController当中有如下回调:
1 [self.delegate setValue:editedSelection forKey:@"editedSelection"];
这句代码调用了BIDTaskListController当中editedSelection属性的setter方法,实现了对数据源的修改,并且在setter方法中刷新了视图:
1 - (void)setEditedSelection:(NSDictionary *)dict { 2 if (![dict isEqual:self.editedSelection]) { 3 _editedSelection = dict; 4 NSIndexPath *indexPath = dict[@"indexPath"]; 5 id newValue = dict[@"object"]; 6 [self.tasks replaceObjectAtIndex:indexPath.row withObject:newValue]; 7 [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 8 withRowAnimation:UITableViewRowAnimationAutomatic]; 9 } 10 }
如此,借助KVC以及回调数据源的setter方法可以彻底解除两个控制器之间的耦合,同时避免了定义协议,使代码更灵活。