认识CoreData—高级用法

  在sectionNameKeyPath:设置属性名后,就以这个属性名作为分组title,相同的title会被分到一个section中。

  初始化FRC时参数managedObjectContext:传入了一个MOC参数,FRC只能监测这个传入的MOC发生的本地持久化改变。就像上面介绍时说的,其他MOC对同一个持久化存储区发生的改变,FRC则不能监测到这个变化。

  再往后面看到cacheName:参数,这个参数我设置的是nil。参数的作用是开启FRC的缓存,对获取的数据进行缓存并指定一个名字。可以通过调用deleteCacheWithName:方法手动删除缓存。

  但是这个缓存并没有必要,缓存是根据NSFetchRequest对象来匹配的,如果当前获取的数据和之前缓存的相匹配则直接拿来用,但是在获取数据时每次获取的数据都可能不同,缓存不能被命中则很难派上用场,而且缓存还占用着内存资源。

  在FRC初始化完成后,调用performFetch:方法来同步获取持久化存储区数据,调用此方法后FRC保存数据的属性才会有值。获取到数据后,调用tableView的reloadData方法,会回调tableView的代理方法,可以在tableView的代理方法中获取到FRC的数据。调用performFetch:方法第一次获取到数据并不会回调FRC代理方法。

  代理方法

  FRC中包含UITableView执行过程中需要的相关数据,可以通过FRC的sections属性,获取一个遵守 协议的对象数组,数组中的对象就代表一个section。

  在这个协议中有如下定义,可以看出这些属性和UITableView的执行流程是紧密相关的。

[email protected] NSFetchedResultsSectionInfo

  /* Name of the section */

[email protected] (nonatomic, readonly) NSString *name;

  /* Title of the section (used when displaying the index) */

[email protected] (nullable, nonatomic, readonly) NSString *indexTitle;

  /* Number of objects in section */

[email protected] (nonatomic, readonly) NSUInteger numberOfObjects;

  /* Returns the array of objects in the section. */

[email protected] (nullable, nonatomic, readonly) NSArray *objects;

[email protected] // NSFetchedResultsSectionInfo

  在使用过程中应该将FRC和UITableView相互嵌套,在FRC的回调方法中嵌套UITableView的视图改变逻辑,在UITableView的回调中嵌套数据更新的逻辑。这样可以始终保证数据和UI的同步,在下面的示例代码中将会演示FRC和UITableView的相互嵌套。

  Table View Delegate

  // 通过FRC的sections数组属性,获取所有section的count值

  - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

  return fetchedResultController.sections.count;

  }

  // 通过当前section的下标从sections数组中取出对应的section对象,并从section对象中获取所有对象count

  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

  return fetchedResultController.sections[section].numberOfObjects;

  }

  // FRC根据indexPath获取托管对象,并给cell赋值

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  Employee *emp = [fetchedResultController objectAtIndexPath:indexPath];

  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier" forIndexPath:indexPath];

  cell.textLabel.text = emp.name;

  return cell;

  }

  // 创建FRC对象时,通过sectionNameKeyPath:传递进去的section title的属性名,在这里获取对应的属性值

  - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

  return fetchedResultController.sections[section].indexTitle;

  }

  // 是否可以编辑

  - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {

  return YES;

  }

  // 这里是简单模拟UI删除cell后,本地持久化区数据和UI同步的操作。在调用下面MOC保存上下文方法后,FRC会回调代理方法并更新UI

  - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

  if (editingStyle == UITableViewCellEditingStyleDelete) {

  // 删除托管对象

  Employee *emp = [fetchedResultController objectAtIndexPath:indexPath];

  [context deleteObject:emp];

  // 保存上下文环境,并做错误处理

  NSError *error = nil;

  if (![context save:&error]) {

  NSLog(@"tableView delete cell error : %@", error);