我在App Store中已有一个使用核心数据来保存数据的应用程序
现在,当iOS 8即将问世时,我想为它添加一个小部件,因此我必须使用App Groups在二进制文件之间共享数据。
但有一个问题 - 我需要更改商店位置以支持应用程序组到所有现有用户
我编写了以下代码,尝试将商店移至新路径:
// 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;
}
输出始终是“已成功迁移到新数据库位置。”,尽管之前保存在应用程序上的所有数据都已删除,就像它创建了一个新数据库而不是仅仅移动它一样。登记/>
是什么原因造成的?我该如何解决?
谢谢。
答案 0 :(得分:16)
使用默认选项创建的核心数据NSSQLiteStoreType存储实际上是几个文件,如Technical Q&A 1809: New default journaling mode for Core Data SQLite stores in iOS 7 and OS X Mavericks中所述。在尝试移动迁移过程中外的商店时,这一点很重要,并且是您的问题的根源 - 当您需要移动所有文件时,您正在移动一个文件。但是,建议不要在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日志选项,这是为了确保如果将来更改默认选项,代码仍然可以工作。如果您使用不同的选项,则应使用它们。
答案 1 :(得分:0)
如果在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()
}
}