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



报告中的最后一个电话是

-[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。

无论如何,您都应该更改该方法,以便仅返回nil或完全运行的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;
}

编辑

评论中没有足够的空间来回答您的问题,因此我在这里提出。



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

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

我并不是要暗示您所做的事情本身就是错误的,只是那不是我要怎么做。

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

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

好吧,这值得比SO答案更深入地介绍,因此我将做简短介绍。它还取决于堆栈的类型-父/子,具有相同PSC的 sibling ,具有不同PSC但商店相同的表亲。

首先,我没有提供对模型和协调器的单独访问。您可以轻松地从上下文访问这些内容,并且通常最终会导致超出其值(value)的问题。

除了测试和简单的示例之外,我总是异步创建我的MOC,就像这样...
+ (void)createWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType
                       completion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion;

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

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

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

10-08 12:15