使用 - [NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]

时间:2015-10-21 05:23:09

标签: ios iphone core-data ios9

我的应用程序最近一直在崩溃,只在iOS9上发生崩溃#

  

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

报告的最后一次电话是

-[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]

这就是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;
}

有人知道造成这些崩溃的原因是什么吗?

2 个答案:

答案 0 :(得分:4)

我在iOS9上没有遇到过这个错误。但是,您应该查看日志以查看您遇到的错误。您是否有可能遇到了#34;错误添加持久存储"创建PSC后?

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

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

无论如何,您应该更改该方法,以便您只返回零或完全可操作的PSC。

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

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

    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSURL *storeURL = [[delegate applicationDocumentsDirectory]
        URLByAppendingPathComponent:@"database.sqlite"];

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]
        initWithManagedObjectModel:self.managedObjectModel];
    NSError *error = nil;
    if (![psc addPersistentStoreWithType:NSSQLiteStoreType
                           configuration:nil
                                     URL:storeURL
                                 options:@{NSMigratePersistentStoresAutomaticallyOption:@YES,
                                           NSInferMappingModelAutomaticallyOption:@YES}
                                   error:&error]) {
        NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo);
    } else {
        _persistentStoreCoordinator = psc;
    }

    return _persistentStoreCoordinator;
}

修改

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

  

@JodyHagins - 另外,你提到你不会构建你的   像这样堆叠,你能让我知道我的堆栈有什么问题吗? -   AWillian

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

然而,该方法表明您从"任何地方访问它是懒惰的#34;这告诉我你的堆栈不是像我构建堆栈那样构建的(特别是因为你还包含了迁移选项)。

我并不意味着暗示你所做的事情本身就是错误的,只是因为我不怎么做。

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

那么,我将如何建立一个堆栈?

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

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

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

+ (void)createWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType
                       completion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion;

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

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

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

答案 1 :(得分:2)

来自Apple开发论坛here的回答,其中也解释了可能的原因和解决方案。

  

原因在于描述符:您的应用程序在设备被锁定时尝试打开持久存储,并且您的代码在数据保护API上跳闸。

     

这就是你在新设备和新iOS版本上绊倒的事情,因为新设备足够快,可以在转换完成数据保护代码之前让你的应用运行。

此类问题的解决方案可能如下所示

  

您几乎必须进入启动代码,然后重写它以便检查受保护数据是否可用,然后延迟启动Core Data,直到applicationProtectedDataDidBecomeAvailable。