在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 導(dǎo)入大數(shù)據(jù)集
與四軸無(wú)人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測(cè)試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動(dòng)開(kāi)發(fā)
Collection View 動(dòng)畫(huà)
截圖測(cè)試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動(dòng)布局工具箱
動(dòng)畫(huà)
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動(dòng)畫(huà)解釋
響應(yīng)式 Android 應(yīng)用
初識(shí) TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測(cè)試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動(dòng)游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動(dòng)畫(huà)
常見(jiàn)的后臺(tái)實(shí)踐
糟糕的測(cè)試
避免濫用單例
數(shù)據(jù)模型和模型對(duì)象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場(chǎng)
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計(jì)
置換測(cè)試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無(wú)人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測(cè)試
值對(duì)象
活動(dòng)追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測(cè)試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場(chǎng)
游戲
調(diào)試核對(duì)清單
View Controller 容器
學(xué)無(wú)止境
XCTest 測(cè)試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動(dòng)畫(huà)
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲(chǔ)
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺(jué)
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫(kù)支持
Fetch 請(qǐng)求
導(dǎo)入大數(shù)據(jù)集
iOS 開(kāi)發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語(yǔ)言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識(shí)別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過(guò)程

導(dǎo)入大數(shù)據(jù)集

往 Core Data 應(yīng)用中導(dǎo)入大數(shù)據(jù)集是個(gè)很常見(jiàn)的問(wèn)題。鑒于數(shù)據(jù)的特點(diǎn)你可以采用以下幾種方法:

  1. 從 web 服務(wù)器上下載數(shù)據(jù) (例如 JSON 數(shù)據(jù)),然后插入到 Core Data 中。
  2. 從 web 服務(wù)器上下載預(yù)先生成的 Core Data SQLite 數(shù)據(jù)庫(kù)文件。
  3. 把一個(gè)預(yù)先生成好的 Core Data SQLite 數(shù)據(jù)庫(kù)文件傳到應(yīng)用程序包中。

對(duì)某些應(yīng)用場(chǎng)景后兩種選擇作為可行的方案經(jīng)常被忽視了。因此,在本文中我們將進(jìn)一步的了解他們,并總結(jié)一下如何高效地把web服務(wù)上的數(shù)據(jù)導(dǎo)入到一個(gè)動(dòng)態(tài)的應(yīng)用中。

傳輸預(yù)先生成的 SQLite 文件

當(dāng)用大量數(shù)據(jù)來(lái)填充 Core Data 時(shí),通過(guò)傳輸或下載預(yù)先生成的 SQLite 文件是一個(gè)可行的方案,并且比在客戶端創(chuàng)建數(shù)據(jù)更加高效。如果源數(shù)據(jù)庫(kù)包含靜態(tài)數(shù)據(jù),并且能夠相對(duì)獨(dú)立地與潛在的用戶產(chǎn)生的數(shù)據(jù)共存,這就是該技術(shù)的使用場(chǎng)景。

Core Data 框架在 iOS 和 OS X 間是共用的,因此,我們可以創(chuàng)建 OS X 上的命令行工具來(lái)產(chǎn)生 SQLite 數(shù)據(jù)庫(kù)文件,并且將該文件用在 iOS 應(yīng)用中。

在我們的例子中 (你可以在 Github 上找到),我們創(chuàng)建了一個(gè)命令行工具,它接受兩個(gè)柏林城市的數(shù)據(jù)集文件作為輸入,并把它們插入到 Core Data SQLite 數(shù)據(jù)庫(kù)中。這個(gè)數(shù)據(jù)集包含大約 13,000 逗留記錄及三百萬(wàn)逗留時(shí)間記錄。

對(duì)于該技術(shù)最重要的是,命令行工具和客戶端應(yīng)用使用了相同的數(shù)據(jù)模型。如果數(shù)據(jù)模型隨著時(shí)間發(fā)生了改變,當(dāng)你更新應(yīng)用并傳輸新的源數(shù)據(jù)時(shí),你要仔細(xì)地管理數(shù)據(jù)模型的版本。有一個(gè)好的建議就是不要復(fù)制.xcdatamodel文件,而是從命令行工具項(xiàng)目中把它鏈接到客戶端應(yīng)用項(xiàng)目。

另一個(gè)有用的步驟是在產(chǎn)生的 SQLite 文件上執(zhí)行 VACUUM 命令。它會(huì)減小文件大小,因此根據(jù)你傳輸文件方式的不同,應(yīng)用程序包的尺寸,或是要下載的數(shù)據(jù)庫(kù)的尺寸也會(huì)相應(yīng)減小。

除了這些,對(duì)于該過(guò)程真的沒(méi)有別的方法了;在我們的案例項(xiàng)目中你也看到了,它就是些簡(jiǎn)單的標(biāo)準(zhǔn) Core Data 代碼。既然生成 SQLite 文件不是性能關(guān)鍵的任務(wù),你也沒(méi)必要花大力氣去優(yōu)化它的性能。如果你想讓它更快,后面針對(duì)高效地導(dǎo)入大數(shù)據(jù)集到動(dòng)態(tài)應(yīng)用中所作的總結(jié)規(guī)則同樣適用。

用戶產(chǎn)生的數(shù)據(jù)

我們經(jīng)常會(huì)有這樣的場(chǎng)景,希望有一個(gè)可用的大的源數(shù)據(jù)集,但是也想能存儲(chǔ)和修改一些用戶產(chǎn)生的數(shù)據(jù)。同樣,有幾種方法來(lái)解決這個(gè)問(wèn)題。

首先要考慮的是,用戶產(chǎn)生的數(shù)據(jù)是否真的需要用 Core Data 來(lái)存儲(chǔ)。如果我們能把這些數(shù)據(jù)存儲(chǔ)到 plist 文件中,就不要亂動(dòng)已建好的 Core Data 數(shù)據(jù)庫(kù)。

如果我們想用 Core Data 來(lái)存儲(chǔ),另一個(gè)需要考慮的問(wèn)題是,在將來(lái)是否需要通過(guò)傳輸更新的預(yù)先建好的 SQLite 文件來(lái)更新源數(shù)據(jù)集。如果這種情況不會(huì)發(fā)生,我們可以安全地把用戶生產(chǎn)的數(shù)據(jù)包含到相同的數(shù)據(jù)模型和配置中。然而,如果我們想傳輸一個(gè)新源數(shù)據(jù)庫(kù),我們必須要分離源數(shù)據(jù)與用戶產(chǎn)生的數(shù)據(jù)。

這個(gè)完全可以通過(guò)建立第二個(gè)完全獨(dú)立的,使用自己的數(shù)據(jù)模型的 Core Data 來(lái)實(shí)現(xiàn),或者通過(guò)在兩個(gè)持久性存儲(chǔ)間分發(fā)相同有數(shù)據(jù)模型的數(shù)據(jù)。對(duì)此,我們需要在同一個(gè)數(shù)據(jù)模型中創(chuàng)建第二個(gè)配置,它保存用戶產(chǎn)生的數(shù)據(jù)的實(shí)體。當(dāng)配置 Core Data 棧時(shí),我們將實(shí)例化兩個(gè)持久化存儲(chǔ),其中一個(gè)包含 URL 和源數(shù)據(jù)庫(kù)的配置,另一個(gè)包含 URL 和用戶產(chǎn)生數(shù)據(jù)的數(shù)據(jù)庫(kù)的配置。

使用兩個(gè)獨(dú)立的 Core Data 棧是一種更簡(jiǎn)單明了的方法。如果這個(gè)方法恰好能解決你的問(wèn)題的話,我們強(qiáng)烈推薦使用它。然而,如果你想在用戶產(chǎn)生的數(shù)據(jù)與源數(shù)據(jù)間建立關(guān)系,Core Data 不能幫你實(shí)現(xiàn)。即使你把所有的東西包含在一個(gè)擴(kuò)展到兩個(gè)持久化存儲(chǔ)的數(shù)據(jù)模型中,你依然不能像通常那樣在這些實(shí)體間定義關(guān)系,但是當(dāng)獲取某一特定屬性時(shí),你可以用 Core Data 中的 fetched properties 從不同的存儲(chǔ)中自動(dòng)獲取對(duì)象。

應(yīng)用 Bundle 中的 SQLite 文件

如果我們想往應(yīng)用程序里傳輸一個(gè)預(yù)先生成的 SQLite 文件,我們必須檢測(cè)出最新更新的應(yīng)用是否是第一次打開(kāi),并把程序外部的數(shù)據(jù)庫(kù)文件復(fù)制到目標(biāo)目錄:

NSFileManager* fileManager = [NSFileManager defaultManager];
NSError *error;

if([fileManager fileExistsAtPath:self.storeURL.path]) {
    NSURL *storeDirectory = [self.storeURL URLByDeletingLastPathComponent];
    NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtURL:storeDirectory
                                          includingPropertiesForKeys:nil
                                                             options:0
                                                        errorHandler:NULL];
    NSString *storeName = [self.storeURL.lastPathComponent stringByDeletingPathExtension];
    for (NSURL *url in enumerator) {
        if (![url.lastPathComponent hasPrefix:storeName]) continue;
        [fileManager removeItemAtURL:url error:&error];
    }
    // 處理錯(cuò)誤
}

NSString* bundleDbPath = [[NSBundle mainBundle] pathForResource:@"seed" ofType:@"sqlite"];
[fileManager copyItemAtPath:bundleDbPath toPath:self.storeURL.path error:&error];

注意我們首先要?jiǎng)h除之前的數(shù)據(jù)庫(kù)文件。這不像你想的那樣簡(jiǎn)單明了,因?yàn)榭赡軙?huì)存在不同的附屬文件(如日志或?qū)懬叭罩疚募┡c主要的 .sqlite 文件相關(guān)。因此我們必須遍歷目錄里的每一項(xiàng),刪除所有的與存儲(chǔ)文件名字匹配不帶擴(kuò)展名的文件。

然而,我們也需要一個(gè)方法確保這件事我們只做了一次。一個(gè)很明顯的方法就是從程序中把源數(shù)據(jù)庫(kù)刪除。雖然在模擬器上管用,但是因?yàn)闄?quán)限的問(wèn)題,在真機(jī)上會(huì)失敗。有很多方案來(lái)解決這個(gè)問(wèn)題,如在 user defaults 中設(shè)置一個(gè) key,它包含了最新導(dǎo)入的數(shù)據(jù)的版本信息:

NSString* bundleVersion = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey];
NSString *seedVersion = [[NSUserDefaults standardUserDefaults] objectForKey@"SeedVersion"];
if (![seedVersion isEqualToString:bundleVersion]) {
    // 復(fù)制源數(shù)據(jù)庫(kù)
}

// ... 導(dǎo)入成功后
NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary;
[[NSUserDefaults standardUserDefaults] setObject:bundleVersion forKey:@"SeedVersion"];

或者舉個(gè)例子,我們也可以復(fù)制存在的數(shù)據(jù)庫(kù)到一個(gè)包含源版本的路徑來(lái)檢測(cè)它是否存在, 從而避免做兩個(gè)相同的導(dǎo)入。有很多可行的方法供你選擇,這取決于你的應(yīng)用場(chǎng)景最重要的是什么。

下載預(yù)先生成的 SQLite 文件

如果出于某些原因我們不想把源數(shù)據(jù)庫(kù)包放在應(yīng)用程序中(如,它會(huì)導(dǎo)致程序大小超過(guò)手機(jī)下載的閾值),我們可以從 web 服務(wù)器上下載。過(guò)程與我們把數(shù)據(jù)庫(kù)文件放在設(shè)備上是一樣的。但是得保證,服務(wù)器提供的數(shù)據(jù)庫(kù)版本要與客戶端的數(shù)據(jù)模型兼容,因?yàn)椴煌膽?yīng)用版本數(shù)據(jù)模型可能會(huì)改變。

這不僅僅是通過(guò)下載來(lái)替換應(yīng)用程序中的一個(gè)文件,這個(gè)方案也使得填充更多的數(shù)據(jù)而不導(dǎo)致在客戶端動(dòng)態(tài)地導(dǎo)入數(shù)據(jù)引發(fā)的性能與電量損耗成為可能。

為了產(chǎn)生馬上可用的 SQLite 文件,我們可以像前面那樣在 (OS X) 服務(wù)器上運(yùn)行類似的命令行導(dǎo)入程序。無(wú)可否認(rèn)地,鑒于數(shù)據(jù)集的大小及要服務(wù)的請(qǐng)求數(shù),對(duì)每一個(gè)請(qǐng)求該操作所需的計(jì)算資源可能不允許。一個(gè)可行的替代方案是定期地生成SQLite文件,給客戶端發(fā)送這些現(xiàn)成的文件。

為了提供 SQLite 下載的 API,在服務(wù)器端及客戶端當(dāng)然需要額外的邏輯,SQLite 的下載可以為自上次源文件生成后已經(jīng)發(fā)生改變的客戶端提供數(shù)據(jù)。整個(gè)過(guò)程有點(diǎn)復(fù)雜,但是可以讓你更容易的用任意大小的動(dòng)態(tài)數(shù)據(jù)來(lái)填充 Core Data,而且沒(méi)有性能問(wèn)題(除了帶寬限制)。

從 Web 服務(wù)導(dǎo)入數(shù)據(jù)

最后,讓我們看看如何從 web 服務(wù)器上導(dǎo)入大量的數(shù)據(jù),如 JSON 格式的數(shù)據(jù)。

如果我們要導(dǎo)入有關(guān)系的不同對(duì)象類型,我們需要在處理它們間的關(guān)系前先獨(dú)立地導(dǎo)入所有的對(duì)象。如果我們能在 server 端保證客戶端是以正確的順序收到的對(duì)象,我們可以馬上處理它們間的關(guān)系,而且不用為此擔(dān)心。但大部分情況這是不可能的。

為在不影響用戶界面響應(yīng)前提下進(jìn)行導(dǎo)入操作,我們必須在后臺(tái)線程中執(zhí)行導(dǎo)入操作。在第二期中,Chris寫了一篇在后臺(tái)使用 Core Data 的簡(jiǎn)單方式。如果做的正確,多核設(shè)備可以在不影響用戶界面響應(yīng)的情況下在后臺(tái)執(zhí)行導(dǎo)入操作。注意,并發(fā)地使用 Core Data 也有可能在不同的托管對(duì)象的上下文間產(chǎn)生沖突。你需要提出一種策略來(lái)預(yù)防或處理這些情況。

在本文中,理解 Core Data 的并發(fā)工作是很重要的。因?yàn)槲覀円呀?jīng)在兩個(gè)線程上建立了兩個(gè)被管理對(duì)象上下文,這并不表示它們兩個(gè)會(huì)同時(shí)去訪問(wèn)數(shù)據(jù)庫(kù)。從托管對(duì)象上下文發(fā)出的每個(gè)請(qǐng)求會(huì)對(duì)上下文的對(duì)象及 SQLite 文件加上鎖。例如,如果你在主上下文的一個(gè)子上下文中觸發(fā)了一個(gè)讀請(qǐng)求,為了執(zhí)行這個(gè)請(qǐng)求,主上下文,持久化存儲(chǔ)協(xié)調(diào)器,持久化存儲(chǔ),以及 SQLite 文件都會(huì)被加鎖(盡管加在 SQLite 文件上的鎖比其他對(duì)象要去除的快)。在此期間,其他在 Core Data 棧上每個(gè)對(duì)象會(huì)被阻塞等著這個(gè)請(qǐng)求的完成。

在后臺(tái)上下文中大量導(dǎo)入數(shù)據(jù)的例子中,這意味著導(dǎo)入操作的保存請(qǐng)求會(huì)不斷地在持久化存儲(chǔ)協(xié)調(diào)器上加鎖。在此期間,像為了更新用戶界面而進(jìn)行的讀取請(qǐng)求,是不能在主上下文中執(zhí)行的,而必須等待保存請(qǐng)求完成。因?yàn)?Core Data 的 API 是同步的,因此主線程會(huì)被阻塞,用戶界面的響應(yīng)會(huì)受影響。

如果在你的應(yīng)用場(chǎng)景中這是個(gè)問(wèn)題,你應(yīng)該考慮為后臺(tái)上下文使用帶有自己的持久化存儲(chǔ)協(xié)調(diào)器的獨(dú)立 Core Data 棧。在這種情況下,在后臺(tái)上下文與主上下文間唯一共享的資源就是 SQLite 文件,鎖競(jìng)爭(zhēng)會(huì)比之前有所減少。特別地,當(dāng) SQLite 文件以 write-ahead loggin 的方式執(zhí)行 (在 iOS7 和 OS X 10.9 是默認(rèn)的) 時(shí),即使在 SQLite 文件級(jí)別,你也會(huì)得到真正并發(fā)。多個(gè)讀和一個(gè)寫可以同時(shí)來(lái)訪問(wèn)數(shù)據(jù)庫(kù)(看這里 WWDC 2013 session "What's New in Core Data and iCloud" )

最后,在大量導(dǎo)入數(shù)據(jù)時(shí),實(shí)時(shí)地把修改通知合并到主上下文中一般不會(huì)是個(gè)好的做法。如果用戶界面對(duì)這些變化自動(dòng)響應(yīng)的話(通過(guò)使用NSFetchResultsController),應(yīng)用界面會(huì)陷入停頓。其實(shí),我們可以在整個(gè)導(dǎo)入完成時(shí)發(fā)送一個(gè)自定義通知,讓用戶界面重新加載數(shù)據(jù)。

如果應(yīng)用場(chǎng)景是想在導(dǎo)入數(shù)據(jù)期間就實(shí)時(shí)的更新UI界面,我們可以考慮過(guò)濾掉特定實(shí)體類型的保存通知,把它們按批聚集起來(lái),或是其他減少界面更新頻率的方式,來(lái)確保界面可以響應(yīng)。然而,在大多數(shù)情況下并不值得這么做,因?yàn)閷?duì)界面的頻繁更新會(huì)讓用戶覺(jué)得更加迷惑,而非更有幫助。

在通過(guò)實(shí)際的導(dǎo)入例子講述了設(shè)置方法和操作手法后,我們?cè)賮?lái)看一些讓它盡可能高效的特殊方法。

高效地導(dǎo)入

為了高效導(dǎo)入數(shù)據(jù),我們的第一個(gè)建議就是通讀 Apple 關(guān)于這個(gè)主題的指導(dǎo)。我們也會(huì)強(qiáng)調(diào)該文檔中經(jīng)常容易被忘記的幾個(gè)方面。

首先,你要在用于導(dǎo)入的上下文中把 undoManager 置為 nil。盡管這個(gè)只適用于 OS X,因?yàn)樵?iOS 上,上下文默認(rèn)沒(méi)有 undo manager。把 undoManager 屬性置空會(huì)帶來(lái)重大的性能提升。

其次,訪問(wèn)具有相互引用關(guān)系的對(duì)象會(huì)產(chǎn)生引用環(huán)。如果你使用了設(shè)計(jì)良好的自動(dòng)釋放池后,還是看到在導(dǎo)入過(guò)程中內(nèi)存使用不斷增加,那就應(yīng)該注意導(dǎo)入部分代碼中的陷阱了。蘋果在這里描述了如何使用refreshObject:mergeChanges:來(lái)去掉這些環(huán)。

當(dāng)你導(dǎo)入可能已經(jīng)在數(shù)據(jù)庫(kù)中存在的數(shù)據(jù)時(shí),你需要實(shí)現(xiàn)一些查找及創(chuàng)建的算法,以防止產(chǎn)生重復(fù)。對(duì)每一個(gè)對(duì)象執(zhí)行讀取請(qǐng)求效率很低,因?yàn)槊總€(gè)讀取請(qǐng)求都需要 Core Data 到硬盤上從存儲(chǔ)文件里讀取數(shù)據(jù)。然而,通過(guò)按批導(dǎo)入數(shù)據(jù)并使用在上面提到的文檔中 Apple 提供的高效查找創(chuàng)建算法,可以很容易避免這個(gè)問(wèn)題。

當(dāng)建立新導(dǎo)入的對(duì)象間的關(guān)系時(shí),類似的問(wèn)題也經(jīng)常產(chǎn)生。用一個(gè)讀取請(qǐng)求獨(dú)立地獲得每一個(gè)相關(guān)的對(duì)象是非常低效的。有兩種可能的解決方法:一是像按批導(dǎo)入數(shù)據(jù)那樣按批處理它們間的關(guān)系,二是緩存已經(jīng)導(dǎo)入的對(duì)象的ID。

按批處理關(guān)系可以使我們大大地減少一次獲取大量相關(guān)對(duì)象的讀取請(qǐng)求次數(shù)。不用擔(dān)心可能很長(zhǎng)的查詢語(yǔ)句,如:

[NSPredicate predicateWithFormat:@"identifier IN %@", identifiersOfRelatedObjects];

處理一個(gè)在IN (...)從句中帶有很多標(biāo)識(shí)符的查詢語(yǔ)句,總是比去硬盤上單獨(dú)地讀取每個(gè)對(duì)象更高效。

然而,也有一種可以完全避免讀取請(qǐng)求的方法,(前提是你只需要在剛導(dǎo)入的對(duì)象間建立關(guān)系)。如果你緩存導(dǎo)入的所有對(duì)象的 IDs (實(shí)際上在大多數(shù)情況下數(shù)據(jù)量也不大),之后你可以用 objectWithID: 方法為相關(guān)的對(duì)象建立關(guān)系。

// 在一堆對(duì)象已經(jīng)被導(dǎo)入并保存之后
for (MyManagedObject *object in importedObjects) {
    objectIDCache[object.identifier] = object.objectID;
}

// ... 之后在解決關(guān)系時(shí)
NSManagedObjectID objectID = objectIDCache[object.foreignKey];
MyManagedObject *relatedObject = [context objectWithID:objectId];
object.toOneRelation = relatedObject;

注意,這個(gè)例子假設(shè) identifier 屬性在所有的實(shí)體類型中是唯一的,否則,我們就得為我們多緩存的不同類型的對(duì)象 IDs 創(chuàng)建重復(fù)的標(biāo)識(shí)符。

結(jié)論

當(dāng)你遇到需要導(dǎo)入大量數(shù)據(jù)到 Core Data 中時(shí),在做大量 JSON 數(shù)據(jù)的實(shí)時(shí)導(dǎo)入前,盡量先不要按常規(guī)來(lái)思考。特別是如果你能控制客戶端和服務(wù)器端,經(jīng)常會(huì)有很多解決該問(wèn)題的高效方法。但是如果你不得不忍痛做大量后臺(tái)導(dǎo)入工作,保證盡可能與主線程一樣獨(dú)立高效地進(jìn)行。

上一篇:KVC 和 KVO下一篇:訪談