更新核心数据存储位置以支持应用程序组

问题描述 投票:0回答:3


我已经在 App Store 中有一个使用核心数据来保存数据的应用程序。
现在,当 iOS 8 即将发布时,我想为其添加一个小部件,因此我必须使用应用程序组在二进制文件之间共享数据。
但有一个问题 - 我需要更改商店位置以支持所有现有用户的应用程序组。
我编写了以下代码,试图将商店移动到新路径:

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *oldStoreURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    oldStoreURL = [oldStoreURL URLByAppendingPathComponent:@"Schooler.sqlite"];


    NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.schooler.mycontainer"];
    storeURL = [storeURL URLByAppendingPathComponent:@"Schooler.sqlite"];


    if([[NSFileManager defaultManager] fileExistsAtPath:oldStoreURL.path] == YES && [[NSFileManager defaultManager] fileExistsAtPath:storeURL.path] == NO)
    {
        // Prior today extension - Need to move to new directory
        NSError *error = nil;
        if([[NSFileManager defaultManager] moveItemAtURL:oldStoreURL toURL:storeURL error:&error] == YES)
            NSLog(@"Migrated successfully to new database location.");
        else
            NSLog(@"error: %@",error);
    }

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }

    return _persistentStoreCoordinator;
}

输出始终是“已成功迁移到新的数据库位置。”,尽管之前保存在应用程序上的所有数据都已被删除,就好像它创建了一个新数据库而不是仅仅移动它一样。

造成问题的原因是什么?我应该如何修复它?
谢谢你。

core-data ios8
3个回答
17
投票

使用默认选项创建的 Core Data NSSQLiteStoreType 存储实际上是多个文件,如技术问答 1809:iOS 7 和 OS X Mavericks 中 Core Data SQLite 存储的新默认日志模式中所述。当尝试将存储移动到迁移过程之外时,记住这一点很重要,这也是问题的根源 - 当您需要移动所有文件时,您正在移动一个文件。但是,不建议在没有文件协调器的情况下将文件单独移到 Core Data 之外。最好使用迁移来代替。 迁移将从源存储中获取数据并将其迁移到新的存储位置,实质上是在新位置复制旧数据。旧数据仍将存在于文件系统上。在您的应用程序中,您应该像现在一样执行迁移,但不要尝试自己将旧数据移动到新位置 - 这就是出现问题的地方。

您可以依靠迁移来为您移动数据,而不是自己移动文件。首先,使用源数据的 URL 将存储添加到持久存储协调器。然后您将执行迁移以将该数据移动到新 URL

NSPersistentStore *sourceStore = nil; NSPersistentStore *destinationStore = nil; NSDictionary *storeOptions = @{ NSSQLitePragmasOption : @{ @"journal_mode" : @"WAL" } }; // Add the source store if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldStoreURL options:storeOptions error:&error]){ // Handle the error } else { sourceStore = [coordinator persistentStoreForURL:oldStoreURL]; if (sourceStore != nil){ // Perform the migration destinationStore = [coordinator migratePersistentStore:sourceStore toURL:storeURL options:storeOptions withType:NSSQLiteStoreType error:&error]; if (destinationStore == nil){ // Handle the migration error } else { // You can now remove the old data at oldStoreURL // Note that you should do this using the NSFileCoordinator/NSFilePresenter APIs, and you should remove the other files // described in QA1809 as well. } } }

迁移完成后,您可以删除旧文件。这里的示例明确指定了 SQLite 日志选项,这是为了确保如果将来更改默认选项,代码仍然可以工作。如果您使用不同的选项,则应该使用这些选项。


2
投票

let oldPersistentStoreURL: URL = ... let sharedPersistentStoreURL: URL = ... let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true] // + any database-specific options if FileManager.default.fileExists(atPath: oldPersistentStoreURL.path) { let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) do { try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: oldPersistentStoreURL, options: options) if let sourceStore = coordinator.persistentStore(for: oldPersistentStoreURL) { let _ = try coordinator.migratePersistentStore(sourceStore, to: sharedPersistentStoreURL, options: options, withType: NSSQLiteStoreType) // If migration was successful then delete the old files } } catch { error.logErrors() } }



0
投票
https://menuplan.app/coding/2021/10/27/core-data-store-path-migration.html

© www.soinside.com 2019 - 2024. All rights reserved.