正文:
在之前的文章中,已經(jīng)講了很多關(guān)于CoreData使用相關(guān)的知識點。這篇文章中主要講兩個方面,NSFetchedResultsController和版本遷移。
文章題目中雖然有“高級”兩個字,其實講的東西并不高級,只是因為上一篇文章中東西太多了,把兩個較復(fù)雜的知識點挪到這篇文章中。
文章中如有疏漏或錯誤,還請各位及時提出,謝謝!
NSFetchedResultsController
在開發(fā)過程中會經(jīng)常用到UITableView這樣的視圖類,這些視圖類需要自己管理其數(shù)據(jù)源,包括網(wǎng)絡(luò)獲取、本地存儲都需要寫代碼進(jìn)行管理。
而在CoreData中提供了NSFetchedResultsController類(fetched results controller,也叫FRC),F(xiàn)RC可以管理UITableView或UICollectionView的數(shù)據(jù)源。這個數(shù)據(jù)源主要指本地持久化的數(shù)據(jù),也可以用這個數(shù)據(jù)源配合著網(wǎng)絡(luò)請求數(shù)據(jù)一起使用,主要看業(yè)務(wù)需求了。
本篇文章會使用UITableView作為視圖類,配合NSFetchedResultsController進(jìn)行后面的演示,UICollectionView配合NSFetchedResultsController的使用也是類似,這里就不都講了。
簡單介紹
就像上面說到的,NSFetchedResultsController就像是上面兩種視圖的數(shù)據(jù)管理者一樣。FRC可以監(jiān)聽一個MOC的改變,如果MOC執(zhí)行了托管對象的增刪改操作,就會對本地持久化數(shù)據(jù)發(fā)生改變,F(xiàn)RC就會回調(diào)對應(yīng)的代理方法,回調(diào)方法的參數(shù)會包括執(zhí)行操作的類型、操作的值、indexPath等參數(shù)。
實際使用時,通過FRC“綁定”一個MOC,將UITableView嵌入在FRC的執(zhí)行流程中。在任何地方對這個“綁定”的MOC存儲區(qū)做修改,都會觸發(fā)FRC的回調(diào)方法,在FRC的回調(diào)方法中嵌入UITableView代碼并做對應(yīng)修改即可。
由此可以看出FRC最大優(yōu)勢就是,始終和本地持久化的數(shù)據(jù)保持統(tǒng)一。只要本地持久化的數(shù)據(jù)發(fā)生改變,就會觸發(fā)FRC的回調(diào)方法,從而在回調(diào)方法中更新上層數(shù)據(jù)源和UI。這種方式講的簡單一點,就可以叫做數(shù)據(jù)帶動UI。

FRC
但是需要注意一點,在FRC的初始化中傳入了一個MOC參數(shù),F(xiàn)RC只能監(jiān)測傳入的MOC發(fā)生的改變。假設(shè)其他MOC對同一個存儲區(qū)發(fā)生了改變,F(xiàn)RC則不能監(jiān)測到這個變化,不會做出任何反應(yīng)。
所以使用FRC時,需要注意FRC只能對一個MOC的變化做出反應(yīng),所以在CoreData持久化層設(shè)計時,盡量一個存儲區(qū)只對應(yīng)一個MOC,或設(shè)置一個負(fù)責(zé)UI的MOC,這在后面多線程部分會詳細(xì)講解。
修改模型文件結(jié)構(gòu)
在寫代碼之前,先對之前的模型文件結(jié)構(gòu)做一些修改。

Employee結(jié)構(gòu)
講FRC的時候,只需要用到Employee這一張表,其他表和設(shè)置直接忽略。需要在Employee原有字段的基礎(chǔ)上,增加一個String類型的sectionName字段,這個字段就是用來存儲section title的,在下面的文章中將會詳細(xì)講到。
初始化FRC
下面例子是比較常用的FRC初始化方式,初始化時指定的MOC,還用之前講過的MOC初始化代碼,UITableView初始化代碼這里也省略了,主要突出FRC的初始化。
// 創(chuàng)建請求對象,并指明操作Employee表
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
// 設(shè)置排序規(guī)則,指明根據(jù)height字段升序排序
NSSortDescriptor *heightSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:YES];
request.sortDescriptors = @[heightSort];
// 創(chuàng)建NSFetchedResultsController控制器實例,并綁定MOC
NSError *error = nil;
fetchedResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:context
sectionNameKeyPath:@"sectionName"
cacheName:nil];
// 設(shè)置代理,并遵守協(xié)議
fetchedResultController.delegate = self;
// 執(zhí)行獲取請求,執(zhí)行后FRC會從持久化存儲區(qū)加載數(shù)據(jù),其他地方可以通過FRC獲取數(shù)據(jù)
[fetchedResultController performFetch:&error];
// 錯誤處理
if (error) {
NSLog(@"NSFetchedResultsController init error : %@", error);
}
// 刷新UI
[tableView reloadData];
在上面初始化FRC時,傳入的sectionNameKeyPath:參數(shù),是指明當(dāng)前托管對象的哪個屬性當(dāng)做section的title,在本文中就是Employee表的sectionName字段為section的title。從NSFetchedResultsSectionInfo協(xié)議的indexTitle屬性獲取這個值。