在sectionNameKeyPath:設置屬性名后,就以這個屬性名作為分組title,相同的title會被分到一個section中。
初始化FRC時參數(shù)managedObjectContext:傳入了一個MOC參數(shù),F(xiàn)RC只能監(jiān)測這個傳入的MOC發(fā)生的本地持久化改變。就像上面介紹時說的,其他MOC對同一個持久化存儲區(qū)發(fā)生的改變,F(xiàn)RC則不能監(jiān)測到這個變化。
再往后面看到cacheName:參數(shù),這個參數(shù)我設置的是nil。參數(shù)的作用是開啟FRC的緩存,對獲取的數(shù)據(jù)進行緩存并指定一個名字??梢酝ㄟ^調用deleteCacheWithName:方法手動刪除緩存。
但是這個緩存并沒有必要,緩存是根據(jù)NSFetchRequest對象來匹配的,如果當前獲取的數(shù)據(jù)和之前緩存的相匹配則直接拿來用,但是在獲取數(shù)據(jù)時每次獲取的數(shù)據(jù)都可能不同,緩存不能被命中則很難派上用場,而且緩存還占用著內存資源。
在FRC初始化完成后,調用performFetch:方法來同步獲取持久化存儲區(qū)數(shù)據(jù),調用此方法后FRC保存數(shù)據(jù)的屬性才會有值。獲取到數(shù)據(jù)后,調用tableView的reloadData方法,會回調tableView的代理方法,可以在tableView的代理方法中獲取到FRC的數(shù)據(jù)。調用performFetch:方法第一次獲取到數(shù)據(jù)并不會回調FRC代理方法。
代理方法
FRC中包含UITableView執(zhí)行過程中需要的相關數(shù)據(jù),可以通過FRC的sections屬性,獲取一個遵守 協(xié)議的對象數(shù)組,數(shù)組中的對象就代表一個section。
在這個協(xié)議中有如下定義,可以看出這些屬性和UITableView的執(zhí)行流程是緊密相關的。
[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的回調中嵌套數(shù)據(jù)更新的邏輯。這樣可以始終保證數(shù)據(jù)和UI的同步,在下面的示例代碼中將會演示FRC和UITableView的相互嵌套。
Table View Delegate
// 通過FRC的sections數(shù)組屬性,獲取所有section的count值
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return fetchedResultController.sections.count;
}
// 通過當前section的下標從sections數(shù)組中取出對應的section對象,并從section對象中獲取所有對象count
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return fetchedResultController.sections[section].numberOfObjects;
}
// FRC根據(jù)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;
}
// 創(chuàng)建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后,本地持久化區(qū)數(shù)據(jù)和UI同步的操作。在調用下面MOC保存上下文方法后,F(xiàn)RC會回調代理方法并更新UI
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// 刪除托管對象
Employee *emp = [fetchedResultController objectAtIndexPath:indexPath];
[context deleteObject:emp];
// 保存上下文環(huán)境,并做錯誤處理
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"tableView delete cell error : %@", error);