KVO 在 UITableView 中观察模型变化的最佳实践

Posted

技术标签:

【中文标题】KVO 在 UITableView 中观察模型变化的最佳实践【英文标题】:Best practice for KVO observing model changes in UITableView 【发布时间】:2013-12-11 13:42:17 【问题描述】:

让我们想象一个基本的 iPhone 应用程序,它有一个表格视图来显示人员列表和一个详细信息视图来更改嵌入在导航控制器中的人的姓名。

我正在使用 KVO 在我的表格视图控制器中收到通知,告知一个人的姓名在详细信息控制器中已更改。

我的问题是何时/在何处添加和删除我的表视图控制器作为每个人对象的 name 的观察者。

我的做法:

@implementation PeopleTableViewController 

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 
    Person *person = ...; // person for index path

    [person addObserver:self forKeyPath:@"name" options:0 context:(__bridge void *)(PERSON_NAME_CTX)];


- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 
    Person *person = ...; // person for index path

    [person removeObserver:self forKeyPath:@"name"];

    // This is not called when the view is removed from the hierarchy
    // Can't use viewDidDisappear: because we are using a navigation controller
    // and tableView:willDisplayCell: is not called when we return from the details controller


- dealloc 
    // See comment in didEndDisplayingCell:

    for (UITableViewCell *cell in self.tableView.visibleCells) 
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

        Person *person = ...; // person for index path

        [person removeObserver:self forKeyPath:@"name"];
    

由于导航控制器,事情有点棘手,因为从视图层次结构中删除视图时不会调用tableView: didEndDisplayingCell。我无法删除viewWillDisappear: 中的观察者,因为当用户从详细信息控制器返回时,我仍然需要观察人员对象的变化。

删除dealloc 中的观察者似乎可行。我的问题:这是正确的做法吗?

【问题讨论】:

【参考方案1】:

通常你应该在 viewWillAppear/viewWillDisappear 方法上分别调用 addObserver/removeObserver,因为 dealloc 方法与这个调用不平衡(我的意思是可以比上面的方法调用几次)。也许最好的解决方案之一是使用 NSFetchedResultsController 来跟踪对数据源的任何更改。

【讨论】:

感谢您的回答。我不使用核心数据,所以我不能使用NSFetchedResultsController。此外,我无法删除viewWillDisappear: 中的观察者,因为我需要通知用户在详细视图控制器中所做的更改。 (我正在使用导航控制器) 我明白了,我认为最好在 viewWillAppear 上执行重新加载数据: 为什么要重新加载?那会起作用,但似乎不对。一切都已经设置好了。导航控制器负责一切。我需要做的就是在另一个视图控制器中的模型更改后更新我的视图。 是的,但请注意,如果所有更改(名称更改)都发生在推送的 viewController 上,则单元格不可见(并且无法更新)。在 viewWillAppear 上重新加载数据是比观察值变化更好的方法。在这种情况下,KVO 没有意义,因为单元格上的更新不是实时的。 好的,我试试 viewWillAppear:。谢谢!

以上是关于KVO 在 UITableView 中观察模型变化的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

iOSKVC 与 KVO

KVO 更新 UITableViewCell

刨根问底KVO原理

KVO:如何告诉观察者,那个自我改变了?

实例被解除分配,而键值观察者仍向其注册

KVO的使用