我正在开发一个仅限 iOS 7 的应用程序,而且我对 iCloud 和 Core 数据还很陌生。我的假设是,如果可能,用户总是希望使用 iCloud 进行备份。这就是为什么我按如下方式设置我的持久性存储:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[[self applicationDocumentsDirectory]
URLByAppendingPathComponent:storeNameWithoutFileExtension isDirectory:NO]
URLByAppendingPathExtension:@"sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(persistentStoreDidImportUbiquitiousContentChanges:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:__persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(storesWillChange:)
name:NSPersistentStoreCoordinatorStoresWillChangeNotification
object:__persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(storesDidChange:)
name:NSPersistentStoreCoordinatorStoresDidChangeNotification
object:__persistentStoreCoordinator];
NSDictionary *options = @{ NSInferMappingModelAutomaticallyOption : @YES,
NSPersistentStoreUbiquitousContentNameKey : storeNameWithoutFileExtension, };
// NSPersistentStoreRebuildFromUbiquitousContentOption
// NSMigratePersistentStoresAutomaticallyOption: @YES,
// NSMigratePersistentStoresAutomaticallyOption : @YES,
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
通过此设置,即使用户未登录 iCloud(使用“本地”文件夹),我也总是立即开始使用 Documents/CoreDataUbiquitySupport 下的文件夹。
如您所见,我正在注册通知。
- 为什么在 NSPersistentStoreCoordinatorStoresWillChangeNotification 和 NSPersistentStoreCoordinatorStoresDidChangeNotification 的 NSNotification 中的键 NSAddedPersistentStoresKey 和 NSRemovedPersistentStoresKey 的数组中添加和删除的持久性存储总是相同的,例如对于添加的案例帐户?人们会期望通知包含已删除的持久性存储和新添加的。所以他们不应该是一样的。但不幸的是,它们总是相同的。
当前的行为是,如果我切换帐户或注销帐户或登录到新帐户,应用程序总是从关联的商店开始,如果以前没有,则使用新的商店。我想要的行为是应用程序始终将数据迁移到新商店。例如:用户未登录 iCloud 并开始使用我的应用程序。他创建了保存在 Documents/CoreDataUbiquitySupport 中的本地数据。现在他打开了 iCloud。现在我希望将本地数据迁移到云端。目前这没有发生。我必须采用哪种方法来实现迁移,我该如何实现呢?我可以使用“migratePersistentStore”方法吗?我尝试在 NSPersistentStoreCoordinatorStoresDidChangeNotification 中使用以下代码,但无济于事:
- (void)storesDidChange:(NSNotification *)n {
// refresh user interface
switch ([[n.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey] integerValue]) {
case NSPersistentStoreUbiquitousTransitionTypeAccountAdded : {
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountAdded migrate");
NSError *error = nil;
NSURL *storeURL = ((NSPersistentStore *)asdf[0]).URL;
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES,
NSPersistentStoreUbiquitousContentNameKey : storeNameWithoutFileExtension, };
NSPersistentStore *asdfasdf = [__persistentStoreCoordinator migratePersistentStore:self.oldStore toURL:storeURL options:options withType:NSSQLiteStoreType error:&error];
}
break;
case NSPersistentStoreUbiquitousTransitionTypeAccountRemoved :
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountRemoved");
break;
case NSPersistentStoreUbiquitousTransitionTypeContentRemoved : {
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeContentRemoved migrate");
NSError *error = nil;
NSURL *storeURL = ((NSPersistentStore *)asdf[0]).URL;
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES,
NSPersistentStoreUbiquitousContentNameKey : storeNameWithoutFileExtension, };
NSPersistentStore *asdfasdf = [__persistentStoreCoordinator migratePersistentStore:self.oldStore toURL:storeURL options:options withType:NSSQLiteStoreType error:&error];
}
break;
case NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted :
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted");
NSLog(@"initial import");
break;
default :
break;
}
}
变量 oldStore 是在 NSPersistentStoreCoordinatorStoresWillChangeNotification 中设置的,因为我不能依赖 NSNotification 及其键 NSAddedPersistentStoresKey 和 NSRemovedPersistentStoresKey 因为如前所述,两个数组始终包含与前面描述的相同的存储。
我将在哪种方法/什么时候实现重复数据删除代码?我可以在其中一个通知中执行此操作吗?
对于哪个用例,我必须使用 NSMigratePersistentStoresAutomaticallyOption?该选项是如何工作的?
我在玩我的应用程序时看到的一个奇怪行为是,如果用户没有登录到 iCloud。当我将我的应用程序带到后台并退出 iCloud 并返回我的应用程序时,我得到的 NSNotifications 的类型是 NSPersistentStoreUbiquitousTransitionTypeContentRemoved。我希望 NSPersistentStoreUbiquitousTransitionTypeAccountRemoved。如果我随后将应用程序置于后台并再次备份,我将获得类型为 NSPersistentStoreUbiquitousTransitionTypeAccountRemoved 的 NSNotifications。但不幸的是,当用户未登录到 iCloud 并且应用程序正在运行并且用户将应用程序带到后台然后回到前台并且我得到类型为 NSPersistentStoreUbiquitousTransitionTypeAccountRemoved 的 NSNotifications 时,NSPersistentStoreCoordinatorStoresWillChangeNotification 和 NSPersistentStoreCoordinatorStoresDidChangeNotification 总是为用例触发。这总是发生。- 这是为什么?
为了使我在这里使用的代码完整,是我的 NSPersistentStoreCoordinatorStoresWillChangeNotification 和 NSPersistentStoreDidImportUbiquitousContentChangesNotification 的代码以及其他几个函数:
- (void)storesWillChange:(NSNotification *)n {
NSLog(@"storesWillChange");
NSArray *pStores = self.persistentStoreCoordinator.persistentStores;
NSManagedObjectContext *moc = [self managedObjectContext];
switch ([[n.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey] integerValue]) {
case NSPersistentStoreUbiquitousTransitionTypeAccountAdded : {
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountAdded");
self.oldStore = pStores[0];
}
break;
case NSPersistentStoreUbiquitousTransitionTypeAccountRemoved :
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountRemoved");
break;
case NSPersistentStoreUbiquitousTransitionTypeContentRemoved :
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeContentRemoved");
self.oldStore = pStores[0];
break;
case NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted :
NSLog(@"NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted");
NSLog(@"initial import");
break;
default :
break;
}
[moc performBlockAndWait:^{
NSError *error = nil;
if ([moc hasChanges]) {
[moc save:&error];
}
[moc reset];
}];
// reset user interface
}
- (void)persistentStoreDidImportUbiquitiousContentChanges:(NSNotification *)changeNotification {
NSLog(@"*** Incoming iCloud Data ***");
NSManagedObjectContext *moc = [self managedObjectContext];
[moc performBlock:^{
[moc mergeChangesFromContextDidSaveNotification:changeNotification];
}];
}
- (NSManagedObjectContext *)managedObjectContext {
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// __managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
[__managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
}
return __managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:dataModelName withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
所以基本上我想要完成的是用户拥有相同的数据,无论他使用哪个 iCloud 帐户,即使它是“本地”的。
任何帮助,将不胜感激。先感谢您!