在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);