使用[[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]在iOS9上崩溃

AWi*_*ian 5 iphone core-data ios ios9

我的应用最近已从仅在iOS9上发生的crashlytics中获取这些崩溃

致命异常:NSInternalInconsistencyException
此NSPersistentStoreCoordinator没有持久存储(损坏的文件)。它无法执行保存操作。

报告中的最后一个电话是

-[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]
Run Code Online (Sandbox Code Playgroud)

这就是NSPersistentStoreCoordinator的创建方式

 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

    NSURL *storeURL = [[delegate applicationDocumentsDirectory] URLByAppendingPathComponent:@"database.sqlite"];

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];

    NSError* error = nil;

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                   configuration:nil
                                                             URL:storeURL
                                                         options:@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} error:&error])
    {
        NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo);
        return nil;
    }

    return _persistentStoreCoordinator;
}
Run Code Online (Sandbox Code Playgroud)

有人知道是什么原因导致这些崩溃吗?

Jod*_*ins 4

我在 iOS9 上没有遇到过这个错误。但是,您应该查看日志以了解有哪些错误。您是否有可能在创建 PSC 时遇到“添加持久性存储时出错”?

\n\n

您的方法有一个问题,如果您遇到该错误,后续调用将返回一个既不为零也不正确设置的 PSC。

\n\n

原因是您_persistentStoreCoordinator在成功设置之前分配了您的。因此,如果出现任何错误,您将返回 nil,但下次调用该方法时,您将返回一个没有存储的 PSC。

\n\n

无论如何,您应该更改该方法,这样您将只返回 nil 或完全可操作的 PSC。

\n\n

我会将该方法更改为类似的方法。 但请注意,我永远不会构建这样的核心数据堆栈。但是,至少以下代码将修复您的错误,您可以在其中返回部分构成的 PSC。

\n\n
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{\n    if (_persistentStoreCoordinator != nil) {\n        return _persistentStoreCoordinator;\n    }\n\n    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;\n    NSURL *storeURL = [[delegate applicationDocumentsDirectory]\n        URLByAppendingPathComponent:@"database.sqlite"];\n\n    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]\n        initWithManagedObjectModel:self.managedObjectModel];\n    NSError *error = nil;\n    if (![psc addPersistentStoreWithType:NSSQLiteStoreType\n                           configuration:nil\n                                     URL:storeURL\n                                 options:@{NSMigratePersistentStoresAutomaticallyOption:@YES,\n                                           NSInferMappingModelAutomaticallyOption:@YES}\n                                   error:&error]) {\n        NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo);\n    } else {\n        _persistentStoreCoordinator = psc;\n    }\n\n    return _persistentStoreCoordinator;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑

\n\n

评论里没有足够的空间来回答你的问题,所以我把它放在这里。

\n\n
\n

@JodyHagins - 另外,你提到你不会像这样构建\n堆栈,你能让我知道我的堆栈出了什么问题吗?\xe2\x80\x93\n 威廉

\n
\n\n

我发表此评论是因为您发布的代码与默认的 Xcode 核心数据模板出奇地相似。你调用app-delegate来获取目录,表明它不在app-delegate中,这很好。

\n\n

但是,该方法表明您从“任何地方”懒惰地访问它,这表明您的堆栈不是按照我构建堆栈的方式构建的(特别是因为您还包括迁移选项)。

\n\n

我并不是想暗示你所做的事情本身就是错误的,只是我不会这么做。

\n\n

现在,我将第一个说我所做的就是我所做的......而且我不会说这是正确的方式......只是我的方式。事实上,我还没有看到其他人真正做我所做的事情(我实际上是 NSManagedObjectContext 的子类,尽管我介意警告并远离那些小气的位)。这本身可能表明我所做的事情可能不适合您或其他任何人。但是,我发现它适合我以及我必须实现的相当复杂的应用程序。

\n\n

那么,我该如何构建堆栈呢?

\n\n

嗯,这值得比如此答案更深入的内容,所以我会简短地说。它还取决于哪种类型的堆栈 - 父/子、具有相同 PSC 的兄弟姐妹、具有不同 PSC 但相同商店的堂兄弟姐妹。

\n\n

首先,我不提供对模型和协调器的单独访问。您可以轻松地从上下文中访问这些内容,但它通常最终会导致比其价值更多的问题。

\n\n

除了测试和简单的例子之外,我总是异步创建我的 MOC,像这样......

\n\n
+ (void)createWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType\n                       completion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion;\n
Run Code Online (Sandbox Code Playgroud)\n\n

MOM 被创建并分配给 PSC,PSC 被创建并分配给 MOC。它是异步发生的,因此可能很长的打开和初始化过程可以在后台线程中完成。完成处理程序在 a 内调用,performBlock因此可以干净地使用 MOC。这也防止了在 MOC 完全设置和读取之前使用。

\n\n

即使使用主队列并发类型调用,所有工作都是在后台线程中完成的,因此仅在主线程上调用完成。

\n\n

在创建用于导入和临时目的的相关 MOC 时,我也使用相同的模式。

\n