Core Data 在近兩代系統(tǒng) iOS 8 和9中得到了大幅強(qiáng)化肖粮,解決了以往性能和批量操作的痛點(diǎn)孤页,主要有以下幾個(gè)新特性:
1.Batch Refresh
2.Batch Update
3.Batch Deletion
4.Asynchronous Fetch
不過(guò),這幾個(gè)新功能的共同特點(diǎn)是:特么都沒(méi)文檔D蜃I⑹!
Core Data 復(fù)習(xí)小圖:
以往我們的更新凌净、刪除操作只有在
NSManagedObjectContext
執(zhí)行保存后才在 Persistent Store 里生效悲龟,然而這個(gè)過(guò)程長(zhǎng)久以來(lái)一直被開(kāi)發(fā)者們?cè)嵅。吮啊atch Update 以及 Batch Deletion 的改進(jìn)在于直接在 Persistent Store 里操作须教,從 WWDC 提供的對(duì)比來(lái)看,速度有了大幅的提升斩芭,更新20000條記錄的速度接近直接使用 SQL 命令轻腺。從上面的類繼承關(guān)系可以看出,
NSFetchRequest
類和其他幾個(gè)類關(guān)系還是挺近的划乖,都是NSPersistentStoreRequest
的子類贬养,使用起來(lái)還是很方便的,只是需要使用新的 API琴庵。
NSManagedObjectContext.executeRequest:error
批量刷新 Batch Refresh
context.refreshAllObjects()
這個(gè)功能姍姍來(lái)遲误算,直到今天的 iOS 9 才到來(lái),在以往要刷新 NSManagedObjectContext 里的所有對(duì)象是很不方便的迷殿,特別是 iOS 8 里添加了 Batch Update 后儿礼,這個(gè)功能簡(jiǎn)直是迫在眉睫了。這個(gè)功能的作用就是我們想象的那樣:
1.刷新在 context 里注冊(cè)的所有對(duì)象的數(shù)據(jù)庆寺,與 Persistent Store 同步;
2.沒(méi)有發(fā)生變化的對(duì)象將會(huì)進(jìn)入 faults 狀態(tài)蚊夫,降低內(nèi)存占用;
3.保留尚未保存的變化懦尝;
4.關(guān)系引用保持有效知纷。
批量更新 Batch Update
BigNerdRanch 出品的使用指南:New in Core Data and iOS 8: Batch Updating壤圃。
批量更新在速度方面有很大提升,內(nèi)存占用也比傳統(tǒng)方案少很多屈扎。示例代碼將所有未讀的郵件標(biāo)記為已讀埃唯,直接在 Persistetn Store 層面操作,性能非常好鹰晨。副作用是:1.更新后不會(huì)主動(dòng)刷新 context;2.更新不會(huì)運(yùn)行有效性驗(yàn)證止毕;3.自己處理沖突模蜡。
let batchUpdateRequest = NSBatchUpdateRequest.init(entityName: "Mail")
batchUpdateRequest.predicate = NSPredicate(format: "read == %@", false)
//propertiesToUpdate 使用 property 為 key,任何 NSExpression 作為值扁凛,這點(diǎn)非常強(qiáng)大忍疾。
batchUpdateRequest.propertiesToUpdate = ["read": true]
batchUpdateRequest.resultType = .UpdatedObjectIDsResultType
context.performBlock(){
do{
let batchUpdateResult = try context.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
if #available(iOS 9, *){
context.refreshAllObjects()
}else{
let updatedIDs = batchUpdateResult.result as! [NSManagedObjectID]
for objectID in updatedIDs{
if let updatedObject = context.objectRegisteredForID(objectID){
context.refreshObject(updatedObject, mergeChanges: true)
}
}
}
} catch {
//Error Handle
}
}
NSBatchUpdateRequest
需要配置的屬性如下:
1.entityName: 指定 entity,用作初始化
2.predicate:用于篩選
3.propertiesToUpdate:更新的鍵值對(duì)
4.resultType:有三種類型谨朝,指定返回值類型卤妒。
NSStatusOnlyResultType:默認(rèn)值,表示操作狀態(tài)字币,成功或失敗
NSUpdatedObjectsCountResultType:返回被更新的數(shù)量
NSUpdatedObjectIDsResultType:返回含有更新對(duì)象的 ObjectID 的數(shù)組
批量刪除 Batch Deletion
批量刪除與上面的批量更新非常類似则披,也是直接在 Persistent Store 里操作。有兩種初始化方式洗出,一種是對(duì)NSFetchRequest
的封裝士复,另一種是指定要?jiǎng)h除對(duì)象的 ObjectID。示例代碼刪除所有垃圾郵件:
if #available(iOS 9.0, *) {
//init with FetchRequest
let fetchRequest = NSFetchRequest.init(entityName: "Mail")
fetchRequest.predicate = NSPredicate(format: "isSpam == %@", true)
let batchDeleteRequest = NSBatchDeleteRequest.init(fetchRequest: fetchRequest)
//Or init with ObjectIDs
let deleteIDs: [NSManagedObjectID] = ...
let batchDeleteRequest = NSBatchDeleteRequest.init(objectIDs: deleteIDs)
context.performBlock(){
do{
try context.executeRequest(batchDeleteRequest)
context.refreshAllObjects()
}catch{
//Error Handle
}
}
}else{
// Fallback on earlier versions
Sample from stack-overflow:(http://stackoverflow.com/questions/1383598/core-data-quickest-way-to-delete-all-instances-of-an-entity/1383645#1383645)
}
NSBatchDeleteRequest
的 resultType 有三種值:
1.NSBatchDeleteResultTypeStatusOnly:默認(rèn)值翩活,不返回任何值
2.NSBatchDeleteResultTypeObjectIDs:返回含有被刪除對(duì)象 ObjectID 的數(shù)組
3.NSBatchDeleteResultTypeCount:返回被刪除的數(shù)量
批量刪除的副作用和批量更新很類似:1.刪除后不更新 context阱洪,不會(huì)發(fā)出通知,因此需要手動(dòng)刷新菠镇;2.不會(huì)運(yùn)行有效性驗(yàn)證(主要是一些關(guān)系的約束)冗荸。
異步獲取 Asynchronous Fetch
BigNerdRanch 出品的使用指南: New in Core Data and iOS 8: Asynchronous Fetching。這個(gè)特性不能算作批量操作的內(nèi)容利耍,但作為一個(gè)有用的特性蚌本,還是記錄下。
Managed Object Context 的 fetch 是同步操作堂竟,雖然我們可以使用多 context 來(lái)解決阻塞主線程的問(wèn)題魂毁,但 fetch 時(shí)依然會(huì)阻塞后臺(tái)進(jìn)程,相對(duì)而言出嘹,異步獲取就解決了這個(gè)問(wèn)題席楚。NSAsynchronousFetchRequest
類在 iOS 8 中推出,但是無(wú)論是文檔還是在 SDK 里的頭文件里都找不到税稼,同級(jí)別的類至少還能在 SDK 的頭文件里找到烦秩,不知為何垮斯。
NSAsynchronousFetchRequest
依然是對(duì)NSFetchRequest
的封裝,由于是異步的只祠,所以搭配了 completionBlock 用于 fetch 完成時(shí)執(zhí)行特定操作兜蠕。基于異步的定位抛寝,Asynchronous Fetch 還配置了顯示 fetch 進(jìn)度和取消 fetch 的功能熊杨。但是,但是盗舰,所有的中間類都找不到文檔和相關(guān)信息晶府,可以說(shuō)這個(gè)特性相當(dāng)?shù)牟挥押茫绻皇翘貏e需要異步特性钻趋,還是別用了吧川陆。