NSFetchedResultsController是为了让视图及时响应Model层的变化而设计的,更具体的将是配合刷新UITableView上的数据。
一般而言,NSFetchedResultsController的实例是由UITableViewController的实例初始化并持有。
创建后,我们将给它分配一个代理(NSFetchedResultsControllerDelegate),当Core Data中的model有变化时,通过代理通知到对应的tableView。
- 对象的新增:新增的对象无法关联到fetchedResultsController,一般是通过 [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:managedObjectContext]的方式初始化并赋值,并保存( [managedObjectContext save:&error]),此处采用的是一致的managedObjectContext,会触发NSFetchedResultsChangeInsert通知。
- 对象的更新:在某些需求中,对象可能是后台异步得到json数据,然后同步进数据库中的。直接对该对象更新,并保存( [managedObjectContext save:&error])。
- 对象的删除:通过在一致的managedObjectContext上删除对应的model对象,会触发NSFetchedResultsChangeDelete通知。并且会将其相关的cascade关系的对象一起删除,无需单独操作。 [post.managedObjectContext deleteObject:post];
官方推荐的方式,是尽量在代理的didChangeObject方法中处理tableView上对section或者row的更新。不管对对象的操作是通过NSArray还是NSFetchedResultsController来获取,亦或是通过insertNewObjectForEntityForName方法去新增,只要是在绑定到代理上的那个controller对象所包含的结果集内的对象有变化,都会触发代理中的didChangeObject方法。
对于对象相关的关系对象变化,比如post对象有个owner对象关系,owner发生了变化,如果会影响结果集,同样会触发post的didChangeObject方法,反之则不会。
遇到最多的问题是相关的model有了更新,并在上下文保存了,但关联的代理的didChangeObject方法中没有被触发,总结了一下,原因主要有几个:
1. managedObejctContext不一致
2. 分析下fetch到controller对应的predicate是否包含受影响的该model,并检查由于该model的相关属性变化后,它对应在结果集中是新增/更新/删除操作,那么在didChangeObject中就会触发到相应的NSFetchedResultsChange
3. 当前返回的controller的delegate是否绑定到对应的代理上了
相关资料: