认识CoreData—高级用法

  正文:

  在之前的文章中,已经讲了很多关于CoreData使用相关的知识点。这篇文章中主要讲两个方面,NSFetchedResultsController和版本迁移。

  文章题目中虽然有“高级”两个字,其实讲的东西并不高级,只是因为上一篇文章中东西太多了,把两个较复杂的知识点挪到这篇文章中。

  文章中如有疏漏或错误,还请各位及时提出,谢谢!

  NSFetchedResultsController

  在开发过程中会经常用到UITableView这样的视图类,这些视图类需要自己管理其数据源,包括网络获取、本地存储都需要写代码进行管理。

  而在CoreData中提供了NSFetchedResultsController类(fetched results controller,也叫FRC),FRC可以管理UITableView或UICollectionView的数据源。这个数据源主要指本地持久化的数据,也可以用这个数据源配合着网络请求数据一起使用,主要看业务需求了。

  本篇文章会使用UITableView作为视图类,配合NSFetchedResultsController进行后面的演示,UICollectionView配合NSFetchedResultsController的使用也是类似,这里就不都讲了。

  简单介绍

  就像上面说到的,NSFetchedResultsController就像是上面两种视图的数据管理者一样。FRC可以监听一个MOC的改变,如果MOC执行了托管对象的增删改操作,就会对本地持久化数据发生改变,FRC就会回调对应的代理方法,回调方法的参数会包括执行操作的类型、操作的值、indexPath等参数。

  实际使用时,通过FRC“绑定”一个MOC,将UITableView嵌入在FRC的执行流程中。在任何地方对这个“绑定”的MOC存储区做修改,都会触发FRC的回调方法,在FRC的回调方法中嵌入UITableView代码并做对应修改即可。

  由此可以看出FRC最大优势就是,始终和本地持久化的数据保持统一。只要本地持久化的数据发生改变,就会触发FRC的回调方法,从而在回调方法中更新上层数据源和UI。这种方式讲的简单一点,就可以叫做数据带动UI。

  FRC

  但是需要注意一点,在FRC的初始化中传入了一个MOC参数,FRC只能监测传入的MOC发生的改变。假设其他MOC对同一个存储区发生了改变,FRC则不能监测到这个变化,不会做出任何反应。

  所以使用FRC时,需要注意FRC只能对一个MOC的变化做出反应,所以在CoreData持久化层设计时,尽量一个存储区只对应一个MOC,或设置一个负责UI的MOC,这在后面多线程部分会详细讲解。

  修改模型文件结构

  在写代码之前,先对之前的模型文件结构做一些修改。

  Employee结构

  讲FRC的时候,只需要用到Employee这一张表,其他表和设置直接忽略。需要在Employee原有字段的基础上,增加一个String类型的sectionName字段,这个字段就是用来存储section title的,在下面的文章中将会详细讲到。

  初始化FRC

  下面例子是比较常用的FRC初始化方式,初始化时指定的MOC,还用之前讲过的MOC初始化代码,UITableView初始化代码这里也省略了,主要突出FRC的初始化。

  // 创建请求对象,并指明操作Employee表

  NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

  // 设置排序规则,指明根据height字段升序排序

  NSSortDescriptor *heightSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:YES];

  request.sortDescriptors = @[heightSort];

  // 创建NSFetchedResultsController控制器实例,并绑定MOC

  NSError *error = nil;

  fetchedResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:request

  managedObjectContext:context

  sectionNameKeyPath:@"sectionName"

  cacheName:nil];

  // 设置代理,并遵守协议

  fetchedResultController.delegate = self;

  // 执行获取请求,执行后FRC会从持久化存储区加载数据,其他地方可以通过FRC获取数据

  [fetchedResultController performFetch:&error];

  // 错误处理

  if (error) {

  NSLog(@"NSFetchedResultsController init error : %@", error);

  }

  // 刷新UI

  [tableView reloadData];

  在上面初始化FRC时,传入的sectionNameKeyPath:参数,是指明当前托管对象的哪个属性当做section的title,在本文中就是Employee表的sectionName字段为section的title。从NSFetchedResultsSectionInfo协议的indexTitle属性获取这个值。