2015-10-21 33 views
4

我的应用程序最近已经从crashlytics让这些崩溃的是仅在iOS9发生崩溃的iOS9用 - [NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]

致命异常: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; 
} 

有人知道这可能是造成这些事故?

回答

3

我在iOS9上没有遇到过这个错误。不过,你应该看看你的日志,看看你有什么错误。是否有可能在创建PSC时遇到了“添加持久存储时出错”?

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

原因在于您在成功设置前指定_persistentStoreCoordinator。因此,如果有任何错误,您将返回零,但下一次您调用该方法时,您将返回一个没有商店的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核心数据模板极其相似。您调用应用程序委托来获取目录,表明这不在应用程序委托中,这很好。

然而,该方法表明你从任何地方懒惰地访问它,这向我表明你的堆栈没有以我将要构建堆栈的方式构建(特别是因为你还包含了用于迁移的选项)。

我不是故意暗示你在做什么是错的,本身就是这样,这不是我该怎么做。现在

,我会是第一个说,我做的是我做什么......我不说这是正确的方式...只是我的方式。实际上,我还没有看到其他人真的在做我所做的事情(我实际上是NSManagedObjectContext的子类,但是我介意警告并远离这些持久位)。这本身可能表明我所做的事可能并不适合你或任何其他人。但是,我发现它适合我,还有我必须实施的非常复杂的应用程序。

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

嗯,这是值得的东西深入比更加如此回答,所以我会尽量简短。它还取决于哪种类型的堆叠 - 父/子,具有相同PSC的兄弟姐妹,具有不同PSC但相同商店的兄弟姐妹。

首先,我不提供单独访问模型和协调器。你可以很容易地从上下文访问那些,并且通常最终导致比它的价值更多的问题。

的测试和简单的例子之外,我始终异步创建我的MOC,这样的事情...

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

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

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

我创造了进口和临时用途相关的MOCS时也使用相同的模式。

+1

我会老老实实地在'NSLog'后添加一个'abort()'来确保这个问题被捕获为一个应用程序没有正确初始化时无用的时间的99.999%。 –

+0

@ MarcusS.Zarra - 同意。 –

+0

感谢您的接触,这似乎是最可能的原因。虽然有趣的是,它开始只发生在iOS9上,我也对[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]意味着什么感兴趣。 – AWillian

2

从苹果开发论坛here这也解释了一个可能的原因和解决方案的回答。

原因是在描述符中:您的应用程序试图在设备被锁定时打开持久性存储,并且您的代码在数据保护API上触发。

这就是你绊倒在新设备和新的iOS版本,因为新设备的速度足以让你的应用程序中的数据保护代码之前运行与过渡做之类的事情。

解决这种问题可以像下面

你很可能进入你的启动时的代码,以便它检查是否受保护的数据是可用的重写,然后延迟您的Core Data启动,直到applicationProtectedDataDidBecomeAvailable。