我正在开发一个仅限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(使用“local”文件夹),我也会立即开始使用Documents / CoreDataUbiquitySupport下的文件夹。
如您所见,我正在注册通知。
目前的行为是,如果我切换帐户或退出帐户或登录到新帐户,应用程序始终以相关商店启动,如果以前没有,则应启动新应用商店。我希望的行为是应用程序始终将数据迁移到新商店。例如:用户未登录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且应用程序正在运行且用户将应用程序带到后台然后返回到前台时,NSPersistentStoreCoordinatorStoresWillChangeNotification和NSPersistentStoreCoordinatorStoresDidChangeNotification将始终为用例触发,我获得类型为NSPersistentStoreUbiquitousTransitionTypeAccountRemoved的NSNotifications。这总是会发生。 - 为什么?
要使我在这里使用的代码完整,我的代码是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帐户,即使它是“本地的”。
任何帮助将不胜感激。提前谢谢!
答案 0 :(得分:2)
要将数据从一个Core Data存储迁移到另一个(无论是否使用iCloud),请使用migratePersistentStore:toURL:options:withType:error:
的{{1}}方法。
但是,确保所有iCloud帐户之间的数据始终相同(已迁移):
从iOS 7开始,iCloud Core Data得到了显着改进,并且大大简化了(对于开发人员而言)。其中一个简化是Core Data现在透明地处理iCloud帐户更改和本地回退存储,并且如果您打开无处不在的商店但用户未登录iCloud,则创建“本地”商店。
不幸的是,这个“本地”商店被视为一个(虚拟)iCloud帐户,因此从它迁移到另一个(真正的)iCloud帐户是棘手的。因此,最好在您的应用中使用“使用iCloud:是/否”选项。如果用户选择“否”,则创建一个真正的本地(不支持iCloud)存储(存储在NSPersistentStoreCoordinator
文件夹中)。现在,当用户更改应用程序中的iCloud选项时,您可以选择将此本地存储迁移到启用iCloud的存储(使用Documents
),反之亦然,如果用户从iCloud切换到本地。
你问的另一个问题是:
我必须使用NSMigratePersistentStoresAutomaticallyOption来使用哪个用例?该选项如何正常工作?
选项migratePersistentStore:toURL:options:withType:error:
和NSMigratePersistentStoresAutomaticallyOption
用于将商店迁移到更新的数据模型(例如,如果您向实体添加字段)并且与之无关从一个商店迁移到另一个商店。它们与您想要解决的问题无关。
答案 1 :(得分:-1)
我建议不要在iOS6中使用iCloud + CoreData。有很多错误。阅读本文:
http://www.theverge.com/2013/3/26/4148628/why-doesnt-icloud-just-work
http://www.zdnet.com/developers-give-apple-an-icloud-ultimatum-fix-it-by-june-7000013495/
修改强>
在iOS7中似乎有所改善,但开发人员说在更改模型版本时会出现问题。 :(