在 iOS 7 中禁用 Core Data 中的 iCloud(也就是将持久存储文件迁移到本地)

Posted

技术标签:

【中文标题】在 iOS 7 中禁用 Core Data 中的 iCloud(也就是将持久存储文件迁移到本地)【英文标题】:Disabling iCloud in Core Data (aka migrating persistantstore file to local) in iOS 7 【发布时间】:2013-11-29 21:37:27 【问题描述】:

我正在使用新的 ios 7 API 将 Core Data 与 iCloud 同步。这是一个非常简单直接的 API,但我找不到禁用它并再次使用本地存储的有效方法。没有数据丢失。

我正在像这样创建我的 iCloud persistantStore。它就像一个魅力。

[[context persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:[self iCloudFilePath]] options:@ NSPersistentStoreUbiquitousContentNameKey: @"Favorite"  error:&error];

但是,我尝试使用新的迁移 API,将商店从 iCloud 商店迁移到本地商店,如下所示:

方法一使用*icloudps作为存储,方法二使用*ps作为存储。

NSPersistentStore *icloudps = [[[context persistentStoreCoordinator]
    persistentStores] objectAtIndex:0];

NSPersistentStore *ps = [[context persistentStoreCoordinator]
    addPersistentStoreWithType:NSSQLiteStoreType
    configuration:nil URL:[icloudps URL] options:nil error:&error];

[[context persistentStoreCoordinator] migratePersistentStore:icloudps
    toURL:[NSURL fileURLWithPath:[self filePath]]
    options:@ NSPersistentStoreRemoveUbiquitousMetadataOption: @YES 
    withType:NSSQLiteStoreType error:&error];

方法 1 导致此崩溃:

由于未捕获的异常而终止应用 'NSObjectInaccessibleException',原因:'CoreData 无法满足 '0xd000000000080002 的故障 x-coredata://153BBFEA-0319-4F10-AEA4-1DA12A21BFFF/Favorite/p2>''

方法二在此:

* 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“nil 不是有效的持久性” 商店'

我不知道如何让它工作。希望有人可以提供帮助。

【问题讨论】:

尝试设置 JOURNAL=DELETE 选项以避免在 WAL 模式下运行。如果现有文件已在 WAL 模式下使用,您可能必须以某种方式强制检查点。 你是对的@DuncanGroenewald。迁移在禁用 WAL 模式的情况下工作。谢谢。 请向 Apple 提交错误报告 好吧,它仍然没有按预期工作。我不确定问题到底出在哪里,在 iCloud 实现中还是在其他地方。 什么不工作? 【参考方案1】:

编辑

我刚刚发布了一个包含 iCloud 集成的示例 iOS 库风格的 Core Data 应用程序。该应用程序包含一个设置包,供用户切换“使用 iCloud”首选项设置,并将根据用户设置将商店迁移到 iCloud 或从 iCloud 迁移。

从下面的链接下载 - 对文档感到抱歉 - 会在某个时候解决这个问题,但它的工作方式与 UIManagedDocument 示例大致相同。

http://ossh.com.au/design-and-technology/software-development/

结束编辑

如果它有任何帮助的话,我在 OS X 上使用的方法是保存 iCloud 同步核心数据文档的另一个副本(以响应用户选择“另存为”菜单选项)。在大多数情况下,iOS 应该以完全相同的方式工作。另请记住,迁移完成后,您可能必须关闭并重新打开文档 - 如果我没有这样做,我似乎记得一些问题。

/*! This method is used to build another local Core Data document, usually in response to the user selecting the 'Save As' menu option.  The document is NEVER iCloud enabled when we do this and the User can select the 'Share in iCloud' menu option once Save As is done to make the file available to other devices via iCloud.

    @param newURL The URL where the new file is to be created.
    @param typeName The type(SQLite, Binary or XML) of file to use for the new store.
    @param error  Upon return contains the error if one was encountered
    @return Returns YES if the new store was successfully created and NO if not.
 */
- (bool)buildNewStoreAtURL:(NSURL*)newURL type:(NSString *)typeName error:(NSError **)error 

    //FLOG(@"buildNewStoreAtURL:type:error: called");

    NSError *myError;

    // We only have one store so get it
    NSPersistentStore *currentStore = [self.managedObjectContext.persistentStoreCoordinator.persistentStores objectAtIndex:0];

    // Get any options it has, we assume we need to keep most of them
    NSDictionary *currentOptions = currentStore.options;

    NSMutableDictionary *newOptions = [[NSMutableDictionary alloc] initWithDictionary:currentOptions];

    // Make sure we don't use WAL mode, it has issues
    [newOptions setObject:@"DELETE" forKey:@"JOURNAL"];

    // Remove any iCloud options (this one includes the unique iCloud UUID)
    [newOptions removeObjectForKey:NSPersistentStoreUbiquitousContentNameKey];

    // Remove Core Data ubiquity metadata
    [newOptions setObject:[NSNumber numberWithBool:YES] forKey:NSPersistentStoreRemoveUbiquitousMetadataOption];

    NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;

    // Now migrate the store to the new location
    NSPersistentStore *newStore = [psc migratePersistentStore:currentStore toURL:newURL options:newOptions withType:typeName error:&myError];

    // Now check it was successful
    if (newStore) 

        // Now set up our custom metadata so we can determine if it has been synced in iCloud next time we open it
        // We have to know this in order to pass in the correct options to the PSC
        NSDictionary *dict = [self getiCloudMetaDataForStore:[psc metadataForPersistentStore:newStore] iCloud:NO ubiquityName:nil];

        [psc setMetadata:dict forPersistentStore:newStore];

        return YES;
    
    else 

        FLOG(@" problem creating new document");
        FLOG(@"  - error is %@, %@", myError, myError.userInfo);
        *error = myError;
        return NO;
    


【讨论】:

我认为关键应该是@"journal_mode" 而不是@"JOURNAL",根据这个:sqlite.org/pragma.html#pragma_journal_mode 和这个:developer.apple.com/library/ios/qa/qa1809/_index.html#//…

以上是关于在 iOS 7 中禁用 Core Data 中的 iCloud(也就是将持久存储文件迁移到本地)的主要内容,如果未能解决你的问题,请参考以下文章

iOS 7 预填充的 Core Data 数据库不包含所有数据

iCloud Core Data iOS 6 到 iOS 7 最初是空的本地后备存储

iOS 7 中的 iCloud、Core Data 和来自 Web 服务的数据

在应用程序运行时启用/禁用 Core Data 的 iCloud 同步

好的教程或适合在 IOS 7 中使用 Core.Data [关闭]

保存在 Core Data 中的 iOS 数据在启动后无法保存