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

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

自定義 Core Data 遷移

自定義 Core Data 遷移似乎是一個不太起眼的話題。蘋果在這方面只提供了很少的文檔,若是初次涉足此方面內(nèi)容,很可能會變成一個可怕的經(jīng)歷。鑒于客戶端程序的性質(zhì),你無法測試你的用戶所生成的數(shù)據(jù)集的所有可能排列。此外,解決遷移過程中出現(xiàn)的問題會很困難,而因為極有可能你的代碼依賴于最新的數(shù)據(jù)模型,所以回退并不是一個可選的處理辦法。

在本文中,我們將走一遍搭建自定義 Core Data 遷移的過程,并著重于數(shù)據(jù)模型的重構(gòu)。我們將探討從舊模型中提取數(shù)據(jù)并使用這些數(shù)據(jù)來填充具有新的實體和關(guān)系的目標(biāo)模型。此外,會有一個包含單元測試的示例項目用于演示兩個自定義遷移。

需要注意的是,如果對數(shù)據(jù)模型的修改只有增加一個實體或可選屬性,輕量級的遷移是一個很好的選擇。它們非常易于設(shè)置,所以本文只會稍稍提及它們。若想知道輕量級遷移的應(yīng)用場合,請查看官方文檔

這就是說,如果你需要快速地在你的數(shù)據(jù)模型上進行相對復(fù)雜的改變,那么自定義遷移就是為你準(zhǔn)備的。

映射模型 (Mapping Models)

當(dāng)你要升級你的數(shù)據(jù)模型到新版,你將先選擇一個基準(zhǔn)模型。對于輕量級遷移,持久化存儲會為你自動推斷一個映射模型。然而,如果你對新模型所做的修改并不被輕量級遷移所支持,那么你就需要創(chuàng)建一個映射模型。一個映射模型需要一個源數(shù)據(jù)模型和一個目標(biāo)數(shù)據(jù)模型。 NSMigrationManager 能夠推斷這兩個模型間的映射模型。這使得它很誘人,可用來一路創(chuàng)建每一個以前的模型到最新模型之間的映射模型,但這很快就會變成一團亂麻。對于每一個新版模型,你需要創(chuàng)建的映射模型的量將線性增長。這可能看起來不是個大問題,但隨之而來的是測試這些映射模型的復(fù)雜度大大提高了。

想像一下你剛剛部署一個包含版本 3 的數(shù)據(jù)模型的更新。你的某個用戶已經(jīng)有一段時間沒有更新你的應(yīng)用了,這個用戶還在版本 1 的數(shù)據(jù)模型上。那么現(xiàn)在你就需要一個從版本 1 到版本 3 的映射模型。同時你也需要版本 2 到版本 3 的映射模型。當(dāng)你添加了版本 4 的數(shù)據(jù)模型后,那你就需要創(chuàng)建三個新的映射模型。顯然這樣做的擴展性很差,那就來試試漸進式遷移吧。

漸進式遷移 (Progressive Migrations)

與其為每個之前的數(shù)據(jù)模型到最新的模型間都建立映射模型,還不如在每兩個連續(xù)的數(shù)據(jù)模型之間創(chuàng)建映射模型。以前面的例子來說,版本 1 和版本 2 之間需要一個映射模型,版本 2 和版本 3 之間需要一個映射模型。這樣就可以從版本 1 遷移到版本 2 再遷移到版本 3。顯然,使用這種遷移的方式時,若用戶在較老的版本上遷移過程就會比較慢,但它能節(jié)省開發(fā)時間并保證健壯性,因為你只需要確保從之前一個模型到新模型的遷移工作正常即可,而更前面的映射模型都已經(jīng)經(jīng)過了測試。

總的想法就是手動找出當(dāng)前版本 v 和版本 v+1 之間的映射模型,在這兩者間遷移,接著繼續(xù)遞歸,直到持久化存儲與當(dāng)前的數(shù)據(jù)模型兼容。

這一過程看起來像下面這樣(完整版可以在示例項目里找到):

- (BOOL)progressivelyMigrateURL:(NSURL *)sourceStoreURL
                         ofType:(NSString *)type
                        toModel:(NSManagedObjectModel *)finalModel
                          error:(NSError **)error
{
    NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:type
                                                                                              URL:sourceStoreURL
                                                                                            error:error];
    if (!sourceMetadata) {
        return NO;
    }
    if ([finalModel isConfiguration:nil
        compatibleWithStoreMetadata:sourceMetadata]) {
        if (NULL != error) {
            *error = nil;
        }
        return YES;
    }
    NSManagedObjectModel *sourceModel = [self sourceModelForSourceMetadata:sourceMetadata];
    NSManagedObjectModel *destinationModel = nil;
    NSMappingModel *mappingModel = nil;
    NSString *modelName = nil;
    if (![self getDestinationModel:&destinationModel
                      mappingModel:&mappingModel
                         modelName:&modelName
                    forSourceModel:sourceModel
                             error:error]) {
        return NO;
    }
    // 我們現(xiàn)在有了一個映射模型,開始遷移
    NSURL *destinationStoreURL = [self destinationStoreURLWithSourceStoreURL:sourceStoreURL
                                                                   modelName:modelName];
    NSMigrationManager *manager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel
                                                                 destinationModel:destinationModel];
    if (![manager migrateStoreFromURL:sourceStoreURL
                                 type:type
                              options:nil
                     withMappingModel:mappingModel
                     toDestinationURL:destinationStoreURL
                      destinationType:type
                   destinationOptions:nil
                                error:error]) {
        return NO;
    }
    // 現(xiàn)在遷移成功了,把文件備份一下以防不測
    if (![self backupSourceStoreAtURL:sourceStoreURL
          movingDestinationStoreAtURL:destinationStoreURL
                                error:error]) {
        return NO;
    }
    // 現(xiàn)在數(shù)據(jù)模型可能還不是“最新”版,所以接著遞歸
    return [self progressivelyMigrateURL:sourceStoreURL
                                  ofType:type
                                 toModel:finalModel
                                   error:error];
}

這段代碼主要來源于 Marcus Zarra,他寫了一本很棒的關(guān)于 Core Data 的書,查看這里。

自 iOS 7 和 OS Mavericks以來,Apple 將 SQLite 的日志模式改寫為預(yù)寫式日志 (Write-Ahead Logging), 這意味著數(shù)據(jù)庫事務(wù)都被依附到一個 -wal 文件中。這有可能導(dǎo)致數(shù)據(jù)丟失和異常。為了數(shù)據(jù)的安全,我們會將日志模式改寫為回溯模式。而如果我們想要遷移數(shù)據(jù)(或者為了以后備份),我們可以將一個字典傳遞給 -addPersistentStoreWithType:configuration:URL:options:error: 來完成改寫。

@{ NSSQLitePragmasOption: @{ @"journal_mode": @"DELETE” } }

NSPersistentStoreCoordinator 相關(guān)的代碼可以在這里找到。

遷移策略

NSEntityMigrationPolicy 是自定義遷移過程的核心。 蘋果的文檔中有這么一句話:

NSEntityMigrationPolicy 的實例為一個實體映射自定義的遷移策略。

簡單的說,這個類讓我們不僅僅能修改實體的屬性和關(guān)系,而且還能任意添加一些自定義的操作來完成每個實體的遷移。

遷移示例

假設(shè)我們有一個帶有簡單的數(shù)據(jù)模型的書籍應(yīng)用。這個模型有兩個實體: UserBookBook 實體有一個屬性叫做 authorName。我們想改善這個模型,添加一個新的實體: Author。同時我們想為 BookAuthor 建立一個多對多的關(guān)系,因為一本書籍可有多個作者,而一個作者也可寫多本書籍。我們將從 Book 對象里取出 authorName 用于填充一個新的實體并建立關(guān)系。

一開始我們要做的是基于第一個數(shù)據(jù)模型增加一個新版模型。在這個例子里,我們添加了一個 Author 實體,它與 Book 還有多對多的關(guān)系。

http://wiki.jikexueyuan.com/project/objc/images/4-3.png" alt="" />

現(xiàn)在數(shù)據(jù)模型已經(jīng)是我們所需要的,但我們還需要遷移所有已存在的數(shù)據(jù),這就該 NSEntityMigrationPolicy 出場了。我們創(chuàng)建 NSEntityMigrationPolicy 的一個子類---- MHWBookToBookPolicy 。在映射模型里,我們選擇 Book 實體并設(shè)置它作為公共部分(Utilities section)中的自定義策略。

http://wiki.jikexueyuan.com/project/objc/images/4-4.png" alt="" />

同時我們使用 user info 字典來設(shè)置一個 modelVersion ,它將在未來的遷移中派上用場。

MHWBookToBookPolicy 中,我們將重載 -createDestinationInstancesForSourceInstance:entityMapping:manager:error: 方法,它允許我們自定義如何遷移每個 Book 實例。如果 modelVersion 的值不是 2,我們將調(diào)用父類的實現(xiàn),否則我們就要做自定義遷移。我們插入基于映射的目標(biāo)實體的新 NSManagedObject 對象到目標(biāo)上下文。然后我們遍歷目標(biāo)實例的屬性鍵值并與來自源實例的值一起填充它們。這將保證我們保留現(xiàn)存數(shù)據(jù)并避免設(shè)置任何我們已經(jīng)在目標(biāo)實例中移除的值。

NSNumber *modelVersion = [mapping.userInfo valueForKey:@"modelVersion"];
if (modelVersion.integerValue == 2) {
    NSMutableArray *sourceKeys = [sourceInstance.entity.attributesByName.allKeys mutableCopy];
    NSDictionary *sourceValues = [sourceInstance dictionaryWithValuesForKeys:sourceKeys];
    NSManagedObject *destinationInstance = [NSEntityDescription insertNewObjectForEntityForName:mapping.destinationEntityName
                                                                         inManagedObjectContext:manager.destinationContext];
    NSArray *destinationKeys = destinationInstance.entity.attributesByName.allKeys;
    for (NSString *key in destinationKeys) {
        id value = [sourceValues valueForKey:key];
        // 避免value為空
        if (value && ![value isEqual:[NSNull null]]) {
            [destinationInstance setValue:value forKey:key];
        }
    }
}

然后我們將基于源實例的值創(chuàng)建一個 Author 實體。但若多本書有同一個作者會發(fā)生什么呢?我們將使用 NSMigrationManager 的一個 category 方法來創(chuàng)建一個查找字典,確保對于同一個名字的作者,我們只會創(chuàng)建一個 Author。

NSMutableDictionary *authorLookup = [manager lookupWithKey:@"authors"];
// 檢查該作者是否已經(jīng)被創(chuàng)建了
NSString *authorName = [sourceInstance valueForKey:@"author"];
NSManagedObject *author = [authorLookup valueForKey:authorName];
if (!author) {
    // 創(chuàng)建作者
    // ...

    // 更新避免重復(fù)
    [authorLookup setValue:author forKey:authorName];
}
[destinationInstance performSelector:@selector(addAuthorsObject:) withObject:author];

最后,我們需要告訴遷移管理器在源存儲與目的存儲之間關(guān)聯(lián)數(shù)據(jù):

[manager associateSourceInstance:sourceInstance
         withDestinationInstance:destinationInstance
                forEntityMapping:mapping];
return YES;

NSMigrationManager 的 category 方法:

@implementation NSMigrationManager (Lookup)

- (NSMutableDictionary *)lookupWithKey:(NSString *)lookupKey
{
    NSMutableDictionary *userInfo = (NSMutableDictionary *)self.userInfo;
    // 這里檢查一下是否已經(jīng)建立了 userInfo 的字典
    if (!userInfo) {
        userInfo = [@{} mutableCopy];
        self.userInfo = userInfo;
    }
    NSMutableDictionary *lookup = [userInfo valueForKey:lookupKey];
    if (!lookup) {
        lookup = [@{} mutableCopy];
        [userInfo setValue:lookup forKey:lookupKey];
    }
    return lookup;
}

@end

一個更復(fù)雜的遷移

過了一會,我們又想把 fileURL 這個屬性從 Book 實體里提出來,放入一個叫做 File 的新實體里。同時我們還想修改實體之間的關(guān)系,以便 User 可與 File 有一對多的關(guān)系,而反過來 FileBook 有多對一的關(guān)系。

http://wiki.jikexueyuan.com/project/objc/images/4-5.png" alt="" />

在之前的遷移中,我們只遷移了一個實體。而現(xiàn)在當(dāng)我們添加了 File 后,事情變得有些復(fù)雜了。我們不能簡單地在遷移一個 Book 時插入一個 File 實體并設(shè)置它與 User 的對應(yīng)關(guān)系,因為此時 User 實體還沒有被遷移,之間的關(guān)系也無從談起。我們必須考慮遷移的執(zhí)行順序。在映射模型中,是可以改變實體映射的順序的。具體到這里的例子,我們想將 UserToUser 映射放在 BookToBook 映射之上。這保證了 User 實體會比 Book 實體更早遷移。

http://wiki.jikexueyuan.com/project/objc/images/4-6.png" alt="" />

添加一個 File 實體的途徑和創(chuàng)建 Author 的過程相似。我們在 MHWBookToBookPolicy 中遷移 Book 實體時創(chuàng)建 File 對象。我們會查看源實例的 User 實體,為每個 User 實體創(chuàng)建一個新的 File 對象,并建立對應(yīng)關(guān)系:

NSArray *users = [sourceInstance valueForKey:@"users"];
for (NSManagedObject *user in users) {

    NSManagedObject *file = [NSEntityDescription insertNewObjectForEntityForName:@"File"
                                                          inManagedObjectContext:manager.destinationContext];
    [file setValue:[sourceInstance valueForKey:@"fileURL"] forKey:@"fileURL"];
    [file setValue:destinationInstance forKey:@"book"];

    NSInteger userId = [[user valueForKey:@"userId"] integerValue];
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
    request.predicate = [NSPredicate predicateWithFormat:@"userId = %d", userId];
    NSManagedObject *user = [[manager.destinationContext executeFetchRequest:request error:nil] lastObject];
    [file setValue:user forKey:@"user"];
}

大數(shù)據(jù)集

如果你的存儲包含了大量數(shù)據(jù),以至到達一個臨界點,遷移就會消耗過多內(nèi)存,Core Data 提供了一個以數(shù)據(jù)塊(chunks)的方式遷移的辦法。蘋果的文檔有簡要地提到這件事。解決辦法是使用多映射模型分開你的遷移并為每個映射模型遷移一次。這要求你有一個對象圖(object graph),在其中,遷移可被分為兩個或多個部分。為了支持這一點而需要添加的代碼其實很少。

首先,我們更新遷移方法以支持使用多個映射模型來遷移。已知映射模型的順序很重要,我們將通過代理方法請求它們:

NSArray *mappingModels = @[mappingModel]; // 我們之前建立的那個模型
if ([self.delegate respondsToSelector:@selector(migrationManager:mappingModelsForSourceModel:)]) {
    NSArray *explicitMappingModels = [self.delegate migrationManager:self
                                         mappingModelsForSourceModel:sourceModel];
    if (0 < explicitMappingModels.count) {
        mappingModels = explicitMappingModels;
    }
}
for (NSMappingModel *mappingModel in mappingModels) {
    didMigrate = [manager migrateStoreFromURL:sourceStoreURL
                                         type:type
                                      options:nil
                             withMappingModel:mappingModel
                             toDestinationURL:destinationStoreURL
                              destinationType:type
                           destinationOptions:nil
                                        error:error];
}

現(xiàn)在,我們?nèi)绾沃獣阅囊粋€映射模型被用于這個特定的源模型呢?此處的 API 可能顯得有些笨拙,但以下的解決方法確實完成了工作。在代理方法中,我們找出源模型的名字并返回相關(guān)的映射模型:

- (NSArray *)migrationManager:(MHWMigrationManager *)migrationManager 
  mappingModelsForSourceModel:(NSManagedObjectModel *)sourceModel
{
    NSMutableArray *mappingModels = [@[] mutableCopy];
    NSString *modelName = [sourceModel mhw_modelName];
    if ([modelName isEqual:@"Model2"]) {
        // 把該映射模型加入數(shù)組
    }
    return mappingModels;
}

我們將為 NSManagedObjectModel 添加一個 category,以幫助我們找出它的文件名: We’ll add a category on NSManagedObjectModel that helps us figure out its filename:

- (NSString *)mhw_modelName
{
    NSString *modelName = nil;
    NSArray *modelPaths = // get paths to all the mom files in the bundle
    for (NSString *modelPath in modelPaths) {
        NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
        NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        if ([model isEqual:self]) {
            modelName = modelURL.lastPathComponent.stringByDeletingPathExtension;
            break;
        }
    }
    return modelName;
}

由于 User 在前面的例子(沒有源關(guān)系映射)中被從對象圖中隔離,因此遷移 User 的過程將省事很多。我們將從第一個映射模型中移除 UserToUser 映射,然后創(chuàng)建一個僅有 UserToUser 的映射。不要忘記在映射模型列表中返回新的 User 映射模型,因為我們正在其它映射中設(shè)置新關(guān)系

單元測試

為此應(yīng)用建立單元測試異常簡單:

  1. 將相關(guān)數(shù)據(jù)填入舊存儲*。
  2. 將產(chǎn)生的持久性存儲文件復(fù)制到你的測試目標(biāo)
  3. 編寫測試斷言符合最新的數(shù)據(jù)模型。
  4. 運行測試,遷移數(shù)據(jù)到新的數(shù)據(jù)模型。

*這很容易完成,只需在模擬器里運行一下你應(yīng)用最新的版本(production version)即可

步驟 1 和 2 很簡單。步驟 3 留給讀者作為練習(xí),然后我會引導(dǎo)你通過第 4 步。

當(dāng)持久化存儲文件被添加到單元測試目標(biāo)上時,我們需要告知遷移管理器把那個存儲遷移至我們的目標(biāo)存儲。在示例項目中所示如下:

- (void)setUpCoreDataStackMigratingFromStoreWithName:(NSString *)name
{
    NSURL *storeURL = [self temporaryRandomURL];
    [self copyStoreWithName:name toURL:storeURL];

    NSURL *momURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
    self.managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];

    NSString *storeType = NSSQLiteStoreType;

    MHWMigrationManager *migrationManager = [MHWMigrationManager new];
    [migrationManager progressivelyMigrateURL:storeURL
                                       ofType:storeType
                                      toModel:self.managedObjectModel
                                        error:nil];

    self.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
    [self.persistentStoreCoordinator addPersistentStoreWithType:storeType
                                                  configuration:nil
                                                            URL:storeURL
                                                        options:nil
                                                          error:nil];

    self.managedObjectContext = [[NSManagedObjectContext alloc] init];
    self.managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
}

- (NSURL *)temporaryRandomURL
{
    NSString *uniqueName = [NSProcessInfo processInfo].globallyUniqueString;
    return [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingString:uniqueName]];
}

- (void)copyStoreWithName:(NSString *)name toURL:(NSURL *)url
{
    // 每次創(chuàng)建一個唯一的url以保證測試正常運行
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSFileManager *fileManager = [NSFileManager new];
    NSString *path = [bundle pathForResource:[name stringByDeletingPathExtension] ofType:name.pathExtension];
    [fileManager copyItemAtPath:path
                         toPath:url.path error:nil];
}

把下面的代碼放到一個父類,以便于在測試的類中復(fù)用:

- (void)setUp
{
    [super setUp];
    [self setUpCoreDataStackMigratingFromStoreWithName:@"Model1.sqlite"];
}

結(jié)論

輕量級遷移是直接在 SQLite 內(nèi)部發(fā)生。這相對于自定義遷移來說非??焖偾矣行?。自定義遷移要把源對象讀入到內(nèi)存中,然后拷貝值到目標(biāo)對象,重新建立關(guān)系,最后插入到新的存儲中。這樣做不僅很慢,而且當(dāng)遷移大數(shù)據(jù)集時,由于內(nèi)存大小的限制,它還會引起系統(tǒng)強制回收內(nèi)存問題。

添加數(shù)據(jù)前盡量考慮完全

在處理任何數(shù)據(jù)持久性問題時最重要的事情之一就是仔細思考你的模型。我們希望模型是可持續(xù)發(fā)展的。在最開始創(chuàng)建模型的時候盡量考慮完全。添加空屬性或者空實體也比以后進行遷移時候創(chuàng)建好的多,因為遷移很容易出現(xiàn)錯誤,而未使用的數(shù)據(jù)就不會了。

調(diào)試遷移

測試遷移時一個有用的啟動參數(shù)是 -com.apple.CoreData.MigrationDebug。設(shè)置為 1 時,你會在控制臺收到關(guān)于遷移數(shù)據(jù)時特殊情況的信息。如果你熟悉 SQL 但不了解 Core Data,設(shè)置 -com.apple.CoreData.SQLDebug 為 1 可在控制臺看到實際操作的 SQL 語句。

上一篇:同步數(shù)據(jù)下一篇:動畫