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

Core data 更新核心数据存储位置以支持应用程序组,core-data,ios8,Core Data,Ios8,我在应用商店中已经有一个应用程序使用核心数据保存数据。 现在,当iOS 8即将面世时,我想给它添加一个小部件,因此我必须使用应用程序组在二进制文件之间共享数据。 但有一个问题-我需要更改商店位置以支持所有现有用户的应用程序组。 我编写了以下代码,试图将存储移动到新路径: // Returns the persistent store coordinator for the application. // If the coordinator doesn't already exist, it i


我在应用商店中已经有一个应用程序使用核心数据保存数据。
现在,当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;
}
输出总是“成功迁移到新数据库位置”,尽管之前保存在应用程序上的所有数据都已被删除,就好像它创建了一个新数据库而不是仅仅移动它一样。

是什么导致了这个问题?我该怎么修

谢谢。

使用默认选项创建的核心数据NSSQLiteStoreType存储实际上是几个文件,如中所述。在尝试将存储移动到迁移过程之外时,请务必记住这一点,这也是问题的根源——当需要移动所有文件时,您正在移动一个文件。但是,不建议在不使用文件协调器的情况下将文件单独移动到核心数据之外。最好使用迁移

迁移将从源存储中获取数据并将其迁移到新存储位置,实际上是在新位置复制旧数据。旧数据仍将存在于文件系统上。在您的应用程序中,您应该像现在一样执行迁移,但不要试图自己将旧数据移动到新位置—这就是问题所在

您可以依靠迁移来移动数据,而不是在自己周围移动文件。首先,使用源数据的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日志选项,这是为了确保如果将来更改了默认选项,代码仍然可以工作。如果您使用的是不同的选项,则应改用这些选项。

如果在Swift中有一个版本会有所帮助:

    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()
        }
    }

非常感谢你帮了我的忙!不用担心,诺姆,很高兴我能帮上忙。祝你的扩展和应用程序好运!要删除这些剩余文件,最好使用NSFileManager的RemoveItemAttribute:。为什么推荐NSFileCoordinator/NSFilePresenter?核心数据在访问默认存储类型中的文件时使用文件协调。如果您要直接访问这些文件(同样,不推荐这样做),您应该只使用文件协调。这样可以确保在核心数据框架使用文件时不会修改文件。在这种情况下,NSFileManager将在文件协调块中使用。同样,执行这些操作的首选方法是通过核心数据API,但如果出于某些奇怪的原因必须直接访问文件,请确保使用文件协调API进行访问。@quellish我使用上述代码尝试将存储从我的应用程序的文档目录移动到组容器,但是
[coordinator migratePersistentStore:sourceStore toURL:storeURL选项:storeOptions withType:NSSQLiteStoreType错误:&error]
始终返回nil,错误也为nil。我尝试使用不同的Tour参数,结果相同。我传递的选项参数是我一直使用的(
@{nsPersistentStoreUbiquityousContentNameKey:@“my~persistent~store~Ubiquity~content~name”}
请在下面的帖子中签出,以获得swift中的解决方案。