成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

初識(shí)CoreData

移動(dòng)開(kāi)發(fā)
這其實(shí)是一篇 WWDC 2015 Session 220 的學(xué)習(xí)筆記,順便整理了下 Core Data 批量操作和聚合操作的小技巧.

這其實(shí)是一篇 WWDC 2015 Session 220 的學(xué)習(xí)筆記,順便整理了下 Core Data 批量操作和聚合操作的小技巧.

批量操作

Core Data 把數(shù)據(jù)庫(kù)封裝成了”object graph(對(duì)象圖)”,雖然對(duì)于面向?qū)ο缶幊虂?lái)說(shuō)有了管理 Model 間繼承與關(guān)系的便利性,但同樣也犧牲了性能.比如批量操作時(shí)就需要將每條記錄作為NSManagedObject 對(duì)象讀取到內(nèi)存中,修改之后再存入數(shù)據(jù)庫(kù).然而用 SQL 語(yǔ)句執(zhí)行既方便又高效.

于是蘋(píng)果在 iOS8 發(fā)布時(shí)順便弄了個(gè)”Batch Updates”,在 iOS9 發(fā)布時(shí)又弄了個(gè)”Batch Deletions”.這兩個(gè)”新技術(shù)”說(shuō)白了就是直接操作持久層數(shù)據(jù)庫(kù),然后還需要手動(dòng)更新/刪除內(nèi)存中的 context 好使得我們的 UI 從 context 讀取的內(nèi)容不會(huì)出錯(cuò).這樣做的好處就是省去了向內(nèi)存的一次寫(xiě)操作和查找操作,而越過(guò) context 直接操作持久層,最后我們需要自己手動(dòng)將持久層的變更結(jié)果(BatchResult)重新寫(xiě)入 context.只有當(dāng)需要更新/刪除大批量數(shù)據(jù)的時(shí)候才需要用到這兩個(gè)技術(shù).

然而蘋(píng)果至今未提供二者的文檔,關(guān)于”Batch Updates”我在CoreData處理海量數(shù)據(jù)中給出了用法和例子.看了 WWDC2015 Session 220 后覺(jué)得 “Batch Deletions” 應(yīng)該與 “Batch Updates” 用法類似,并且坑爹. PS: 我在 iOS9 上測(cè)試 “Batch Updates” 發(fā)現(xiàn)了一個(gè) bug, 每次更新 context 都會(huì)漏掉一條記錄,這讓我十分郁悶.

聚合操作

說(shuō)完了批量操作,再談?wù)劸酆喜僮?在 SQL 語(yǔ)法中有一類聚合函數(shù),比如count(),sum(),max(),min(),avg() 等,它們一般搭配著 group by 甚至 having來(lái)使用.然而在號(hào)稱”object graph”的 Core Data 中,這種聚合操作在 NSFetchRequest 中也是有替代品的.下面的例子取自CORE DATA AND AGGREGATE FETCHES IN SWIFT:

我們想計(jì)算出每條產(chǎn)品線的銷售量和退貨量,可以用下面的 SQL 語(yǔ)句搞定:

  1. SELECT ProductLine, SUM(Sold) as SoldCount, SUM(Returned) as ReturnedCount FROM Products GROUP BY ProductLine 

NSFetchRequest 有個(gè) propertiesToGroupBy 屬性,正好對(duì)應(yīng)著 group by 語(yǔ)句:

  1. // Build out our fetch request the usual way 
  2. let request = NSFetchRequest(entityName: self.entityName) 
  3. // This is the column we are grouping by. Notice this is the only non aggregate column. 
  4. request.propertiesToGroupBy = ["productLine"

下面還需要映射 SQL 語(yǔ)句中聚合函數(shù)及其計(jì)算后的結(jié)果,此時(shí)我們需要用到NSExpressionDescription 和 NSExpression 來(lái)替換 SQL 中的ProductLine, SUM(Sold) as SoldCount, SUM(Returned) as ReturnedCount:

  1. // Create an array of AnyObject since it needs to contain multiple types--strings and 
  2. // NSExpressionDescriptions 
  3. var expressionDescriptions = [AnyObject]() 
  4.      
  5. // We want productLine to be one of the columns returned, so just add it as a string 
  6. expressionDescriptions.append("productLine"
  7.      
  8.  
  9.  
  10. // Create an expression description for our SoldCount column 
  11. var expressionDescription = NSExpressionDescription() 
  12. // Name the column 
  13. expressionDescription.name = "SoldCount" 
  14. // Use an expression to specify what aggregate action we want to take and 
  15. // on which column. In this case sum on the sold column 
  16. expressionDescription.expression = NSExpression(format: "@sum.sold"
  17. // Specify the return type we expect 
  18. expressionDescription.expressionResultType = .Integer32AttributeType 
  19. // Append the description to our array 
  20. expressionDescriptions.append(expressionDescription) 
  21.  
  22.  
  23.      
  24. // Create an expression description for our ReturnedCount column 
  25. expressionDescription = NSExpressionDescription() 
  26. // Name the column 
  27. expressionDescription.name = "ReturnedCount" 
  28. // Use an expression to specify what aggregate action we want to take and 
  29. // on which column. In this case sum on the returned column 
  30. expressionDescription.expression = NSExpression(format: "@sum.returned"
  31. // Specify the return type we expect 
  32. expressionDescription.expressionResultType = .Integer32AttributeType 
  33. // Append the description to our array 
  34. expressionDescriptions.append(expressionDescription) 

NSExpressionDescription 是用于表示那些抓取結(jié)果中實(shí)體中不存在的列名,比如我們這次用的聚合函數(shù)所計(jì)算的結(jié)果并不能在實(shí)體中找到對(duì)應(yīng)的列,于是我們就得給它起個(gè)新名字,這就相當(dāng)于 SQL 中的 as,這里對(duì)應(yīng)著 NSExpressionDescription 的 name 屬性.而聚合函數(shù)表達(dá)式就需要用 NSExpression 對(duì)象來(lái)表示,比如 NSExpression(format: "@sum.returned")就是對(duì)”returned”這列求和.

像本例中這樣初始化 NSExpression 需要對(duì)格式化語(yǔ)法較為熟悉(比如"@sum.returned"),初學(xué)者建議看看官方的例子,使用容易理解的構(gòu)造方法一步步拼湊成想要的結(jié)果:Core Data Programming Guide

將以上這三個(gè)”列描述”依次添加到 expressionDescriptions 數(shù)組中,最后要賦值給NSFetchRequest 的 propertiesToFetch 屬性:

  1. // Hand off our expression descriptions to the propertiesToFetch field. Expressed as strings 
  2. // these are ["productLine", "SoldCount", "ReturnedCount"] where productLine is the value 
  3. // we are grouping by. 
  4. request.propertiesToFetch = expressionDescriptions 

propertiesToFetch 屬性其實(shí)是個(gè) NSPropertyDescription 類型數(shù)組,能表示屬性,一對(duì)一關(guān)系和表達(dá)式.既然是個(gè)大雜燴,NSPropertyDescription 也就有一些子類:NSAttributeDescription,NSExpressionDescription,NSFetchedPropertyDescription,NSRelationshipDescription.我們這里用到的便是 NSExpressionDescription.

在設(shè)定 propertiesToFetch 屬性之前必需要設(shè)定好 NSFetchRequest 的 entity 屬性,否則會(huì)拋出 NSInvalidArgumentException 類型的異常.并且只有當(dāng) resultType 類型設(shè)為NSDictionaryResultType 時(shí)才生效:

  1. // Specify we want dictionaries to be returned 
  2. request.resultType = .DictionaryResultType 

最終結(jié)果:

  1.     ["SoldCount"48"productLine": Bowler, "ReturnedCount"4],  
  2.     ["SoldCount"142"productLine": Stetson, "ReturnedCount"27],  
  3.     ["SoldCount"50"productLine": Top Hat, "ReturnedCount"6

WWDC2015 Core Data 的一些新特性

蘋(píng)果號(hào)稱有超過(guò)40萬(wàn)個(gè) APP 使用 Core Data,并能讓開(kāi)發(fā)者少寫(xiě)50%~70%的代碼.并在內(nèi)存性能上強(qiáng)調(diào)卓越的內(nèi)存拓展和主動(dòng)式惰性加載,炫耀了它跟 UI 良好的綁定機(jī)制,還提供了幾種多重寫(xiě)入的合并策略.然而這不能阻止開(kāi)發(fā)者對(duì) Core Data 的吐槽,畢竟建立于持久層之上的”object graph”還做不到像 SQL 那樣面面俱到,于是今年針對(duì) Core Data 新增的 API 更像是查缺補(bǔ)漏,并沒(méi)有帶來(lái)重大功能更新.

NSManagedObject 新增 API

hasPersistentChangedValues

  1. var hasPersistentChangedValues: Bool { get } 

用此屬性可確定 NSManagedObject 的值與 “persistent store” 是否相同.

objectIDsForRelationshipNamed

  1. func objectIDsForRelationshipNamed(_ key: String) -> [NSManagedObjectID] 

適用于大量的多對(duì)多關(guān)系.由于我們不想將整個(gè)關(guān)系網(wǎng)絡(luò)加載到內(nèi)存中,所以這個(gè)方法僅返回相關(guān)聯(lián)的 ID.下面是一個(gè)例子:

  1. let relations = person.objectIDsForRelationshipNamed("family"
  2.  
  3. let fetchFamily = NSFetchRequest(entityName:"Person"
  4. fetchFamily.fetchBatchSize = 100 
  5. fetchFamily.predicate = NSPredicate(format: "self IN %@", relations) 
  6.  
  7. let batchedRelations = managedObjectContext.executeFetchRequest(fetchFamily) 
  8.  
  9. for relative in batchedRelations { 
  10.     //work with relations 100 rows at a time 

通過(guò)給出的關(guān)系名稱 “family” 來(lái)獲取對(duì)應(yīng)的 ID, 并每次遍歷100行記錄,實(shí)現(xiàn)了內(nèi)存占用的可控性.

#p#

NSManagedObjectContext 新增 API

refreshAllObjects

  1. func refreshAllObjects() 

正如其名字所描述的那樣,它的功能就是刷新 context 中所有對(duì)象,但會(huì)保留未保存的變更.相比reset 方法不同的是它會(huì)依然保留 NSManagedObject 對(duì)象的有效性,我們無(wú)需重新抓取任何對(duì)象.正因如此,它很適用于打破一些因遍歷雙向關(guān)系循環(huán)而產(chǎn)生的保留環(huán).

mergeChangesFromRemoteContextSave

  1. class func mergeChangesFromRemoteContextSave(_ changeNotificationData: [NSObject : AnyObject], intoContexts contexts: [NSManagedObjectContext]) 

在 store 中使用多個(gè) coordinator 時(shí),這個(gè)方法將會(huì)從一個(gè) coordinator 接受一個(gè)通知,并將其應(yīng)用到另一個(gè) coordinator 中的 context 上.這使得我們可以在所有 context 中存有最新的數(shù)據(jù),Core Data 會(huì)維護(hù)好所有的 context.

shouldDeleteInaccessibleFaults

  1. var shouldDeleteInaccessibleFaults: Bool 

Core Data 偶爾會(huì)拋異常,但Core Data 不能加載故障, 因?yàn)樗闹鲃?dòng)式惰性加載對(duì)象使得內(nèi)存中只保留對(duì)象圖中的一部分.所以很有可能當(dāng)我遍歷關(guān)系時(shí)要試圖回到磁盤(pán)上查找,但此時(shí)對(duì)象早已被刪除了.于是 shouldDeleteInaccessibleFaults 屬性應(yīng)運(yùn)而生,默認(rèn)值為 YES.

如果我們?cè)谀程幱龅搅斯收?我們會(huì)將其標(biāo)記為已刪除.任何丟失的屬性將會(huì)被設(shè)為null,nil或0.這就使得我們的 app 繼續(xù)運(yùn)行,并認(rèn)為發(fā)生故障的對(duì)象已被刪除.這樣程序就不會(huì)再崩潰.

NSPersistentStoreCoordinator 新增 API

增加這兩個(gè)新的 API 的原因是很多開(kāi)發(fā)者繞過(guò) Core Data 的 API 來(lái)直接操作底層數(shù)據(jù)庫(kù)文件.因?yàn)镹SFileManager 和 POSIX 對(duì)數(shù)據(jù)庫(kù)都不友好,并且如果此時(shí)文件的 open 連接沒(méi)關(guān)閉的話會(huì)損壞文件.

destroyPersistentStoreAtURL

  1. func destroyPersistentStoreAtURL(_ url: NSURL, withType storeType: String, options options: [NSObject : AnyObject]?) throws 

傳入的選項(xiàng)與 addPersistentStoreWithType 方法要一樣,刪除對(duì)應(yīng)類型的 persistent store.

replacePersistentStoreAtURL

  1. func replacePersistentStoreAtURL(_ destinationURL: NSURL, destinationOptions destinationOptions: [NSObject : AnyObject]?, withPersistentStoreFromURL sourceURL: NSURL, sourceOptions sourceOptions: [NSObject : AnyObject]?, storeType storeType: String) throws 

與上面的 destroy 一個(gè)套路,就是 replace 而已.如果目標(biāo)位置不存在數(shù)據(jù)庫(kù),那么這個(gè) replace 就相當(dāng)于拷貝操作了.

Unique Constraints

很多時(shí)候我們?cè)趧?chuàng)建一個(gè)對(duì)象之前會(huì)查看它是否已經(jīng)存在,如果存在的話就會(huì)更新它,否則就創(chuàng)建對(duì)象.這很可能產(chǎn)生一個(gè)競(jìng)態(tài)條件,如果多線程同時(shí)執(zhí)行下面這段代碼, 很可能就創(chuàng)建了多個(gè)重復(fù)的對(duì)象:

  1. managedObjectContext.performBlock { 
  2.     let createRequest = NSFetchRequest(entityName: "Recipe"
  3.     createRequest.resultType = ManagedObjectIDResultType 
  4.     let predicate = NSPredicate(format: "source = %@", source) 
  5.     let results = managedObjectContext.executeFetchRequest(createRequest) 
  6.     if (results.count) { 
  7.         //update it! 
  8.     } else { 
  9.         //create it! 
  10.     } 

現(xiàn)在 Core Data 可以搞定這個(gè)事情了.我們?cè)O(shè)定屬性的值唯一,類似于 SQL 中的 unique 約束.諸如電子郵件,電話號(hào), ISBN 等場(chǎng)景都適用此.同時(shí)別忘了 Core Data 的對(duì)象圖中實(shí)體的繼承關(guān)系,這里規(guī)定子類會(huì)從父類繼承到具有 Unique 約束的屬性,并可以將更多的屬性設(shè)為 Unique.

為實(shí)體設(shè)置 Unique 屬性十分簡(jiǎn)單,只需要在 Xcode 中選中對(duì)應(yīng)的實(shí)體,打開(kāi) “Data Model inspector” 就可以看到 “Constraints”, 點(diǎn)擊加號(hào)添加就好:

Model Caching

這是個(gè)輕量級(jí)的數(shù)據(jù)版本自動(dòng)遷移解決方案.它會(huì)緩存舊版本數(shù)據(jù)中已創(chuàng)建的NSManagedObject 對(duì)象會(huì)被緩存到 store 中,并被遷移到合適的 store 中.

Generated Subclasses

在 Xcode7 中,自動(dòng)創(chuàng)建 NSManagedObject 子類時(shí)將不再在對(duì)應(yīng)實(shí)體子類文件中自動(dòng)填充模板代碼,而是同時(shí)創(chuàng)建Category(Objective-C文件) 或 extension(Swift文件),并將模板代碼自動(dòng)填寫(xiě)進(jìn)去.這樣帶來(lái)的好處是將我們自己寫(xiě)的代碼跟 Xcode 生成的模板代碼分開(kāi),更易于更新維護(hù).

責(zé)任編輯:倪明 來(lái)源: 玉令天下的博客
相關(guān)推薦

2011-07-08 17:57:37

iPhone CoreData 數(shù)據(jù)庫(kù)

2015-03-12 09:51:09

CoreDataiCloud

2015-06-11 15:25:43

ASP.NET

2014-07-24 09:22:37

iOS 8OS XCoreData

2010-07-25 14:37:40

telnet命令

2010-09-10 14:25:00

Daytime協(xié)議

2012-03-05 13:41:58

OpenFlow

2010-07-12 17:02:33

Netstat TCP

2010-09-09 17:05:37

PPPoE協(xié)議

2010-07-08 12:34:46

HART協(xié)議

2011-07-01 16:04:45

Qt Python

2010-09-17 15:28:45

Internet網(wǎng)絡(luò)協(xié)

2011-06-14 14:41:14

Python Qt

2011-06-14 15:45:02

Qt Object

2010-08-31 16:03:15

2011-06-14 17:03:03

QML Qt

2022-08-05 11:33:40

云計(jì)算

2024-10-28 08:15:32

2021-03-26 14:00:27

物聯(lián)網(wǎng)藍(lán)牙低功耗

2017-09-06 14:51:21

Swift
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 97av| 精品国产精品一区二区夜夜嗨 | 91资源在线| 亚洲欧美日韩精品久久亚洲区 | 亚洲人人 | 亚洲精品在 | 欧美一区二区在线看 | 国户精品久久久久久久久久久不卡 | 午夜精品久久久久久 | 成人在线不卡 | 婷婷成人在线 | 国精久久 | 国产亚洲精品久久久久久豆腐 | 香蕉91| 免费看一区二区三区 | 精品国产精品国产偷麻豆 | 中文字幕日韩欧美一区二区三区 | 亚洲成人免费av | 99热首页 | 91xxx在线观看 | 日本不卡一区 | 久久久高清 | 中文字幕一区二区三区四区五区 | 亚洲一区二区三区免费 | 中日字幕大片在线播放 | 成人不卡 | 久草热视频 | 亚洲福利在线视频 | 韩国av一区二区 | 亚洲一区二区在线播放 | 国产精品视频在线观看 | 国产激情精品一区二区三区 | 爱综合| 黄网站免费观看 | 国产精品揄拍一区二区 | 国产精品久久久久999 | 一区二区三区视频在线免费观看 | 亚洲狠狠| a级片www | 国产精品亚洲一区二区三区在线 | 国产一二三区免费视频 |