gpt4 book ai didi

ios - iCloud 核心数据迁移

转载 作者:行者123 更新时间:2023-11-29 13:02:37 24 4
gpt4 key购买 nike

我正在开发一个仅限 iOS 7 的应用程序,而且我对 iCloud 和核心数据还很陌生。我的假设是用户总是希望尽可能使用 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;

}

通过此设置,我总是立即开始使用 Documents/CoreDataUbiquitySupport 下的文件夹,即使用户未登录 iCloud(使用“本地”文件夹)也是如此。

如您所见,我正在注册通知。

  • 为什么 NSPersistentStoreCoordinatorStoresWillChangeNotification 和 NSPersistentStoreCoordinatorStoresDidChangeNotification 的 NSNotifications 中的键 NSAddedPersistentStoresKey 和 NSRemovedPersistentStoresKey 数组中添加和删除的持久性存储总是相同的,例如对于添加的案例帐户?人们会期望通知包含已删除的持久性存储和新添加的持久性存储。所以他们不应该是一样的。但不幸的是,它们总是一样的。

当前的行为是,如果我切换帐户或注销帐户或登录新帐户,应用程序总是从关联的商店开始,如果之前没有,则从新的商店开始。我期望的行为是应用程序始终将数据迁移到新商店。例如:用户未登录 iCloud 并开始使用我的应用程序。他创建的数据保存在本地文件/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。但不幸的是,NSPersistentStoreCoordinatorStoresWillChangeNotification 和 NSPersistentStoreCoordinatorStoresDidChangeNotification 在用户未登录 iCloud 且应用程序正在运行并且用户将应用程序置于后台然后返回前台时始终为用例触发,我得到类型为 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 帐户,用户都拥有相同的数据,即使它是“本地”。

如有任何帮助,我们将不胜感激。提前致谢!

最佳答案

要将数据从一个 Core Data 存储迁移到另一个(无论是否使用 iCloud),请使用 NSPersistentStoreCoordinatormigratePersistentStore:toURL:options:withType:error: 方法。

但是,确保您的数据在所有 iCloud 帐户之间始终相同(迁移)是:

  • 可能很难(至少我不知道你会怎么做)。
  • 可能不是您的用户想要的。每个 iCloud 帐户都有自己的数据是有意义的。

从 iOS 7 开始,iCloud 核心数据得到了显着改进和极大简化(对于开发人员而言)。其中一项简化是 Core Data 现在可以透明地处理 iCloud 帐户更改和本地后备存储,如果您打开一个无处不在的存储但用户没有登录 iCloud,则可以创建“本地”存储。

不幸的是,这个“本地”商店被视为一个(虚拟的)iCloud 帐户,因此从它迁移到另一个(真实的)iCloud 帐户是很棘手的。因此,最好在您的应用程序中添加“使用 iCloud:是/否”选项。如果用户选择“否”,则创建一个真正的本地(未启用 iCloud)存储(存储在 Documents 文件夹中)。现在,当用户在您的应用程序中更改 iCloud 选项时,您可以选择将此本地商店迁移到支持 iCloud 的商店(使用 migratePersistentStore:toURL:options:withType:error:),并且副如果用户从 iCloud 切换到本地,则相反。

你问的另一个问题是:

For which usecase do I have to use NSMigratePersistentStoresAutomaticallyOption? How does that option work exactly?

选项 NSMigratePersistentStoresAutomaticallyOptionNSInferMappingModelAutomaticallyOption 用于将商店迁移到更新的数据模型(例如,如果您向实体添加字段)与从一家商店迁移到另一家商店无关。它们与您要在此处解决的问题无关。

关于ios - iCloud 核心数据迁移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19432545/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com