在iOS9上崩溃 –

我的应用程序最近从崩溃解决方案中获得了这些崩溃,这只是在iOS9上发生的

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

谁知道可能导致这些崩溃的原因是什么?

我没有在iOS9上遇到过这个错误。 但是,您应该查看日志以查看您遇到的错误。 您是否有可能在创建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中,这很好。

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

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

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

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

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

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

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

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

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

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

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

来自Apple dev论坛的回答也解释了可能的原因和解决方案。

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

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

解决这类问题的方法如下

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