【问题标题】:This NSPersistentStoreCoordinator has no persistent stores (device locked). It cannot perform a save operation. specialized static method这个 NSPersistentStoreCoordinator 没有持久存储(设备锁定)。它无法执行保存操作。专门的静态方法
【发布时间】:2019-11-12 22:14:18
【问题描述】:

在尝试保存或更新记录时,应用程序在生产中随机崩溃。

这是一个 VOIP 应用程序,获取后台 CallKit 推送,并且在某些情况下,将它们写入 CoreDate DB。我怀疑这就是导致应用程序崩溃的原因,但我在网上找不到任何关于它的参考资料。

尝试在本地重现此问题但没有成功,可能是因为在您第一次解锁手机之前无法使用 Xcode 进行调试。

这是我来自 AppDelegate 的 CoreDate 代码:

    lazy var persistentContainer: NSPersistentContainer = {

        let container = NSPersistentContainer(name: "Model")

        var persistentStoreDescriptions: NSPersistentStoreDescription

        let storeUrl =  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.appname")!.appendingPathComponent("Model.sqlite")


        let description = NSPersistentStoreDescription()
        description.shouldInferMappingModelAutomatically = true
        description.shouldMigrateStoreAutomatically = true
        description.url = storeUrl

        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url:  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.appname")!.appendingPathComponent("Model.sqlite"))]

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                Crashlytics.sharedInstance().recordError(error)
                #if DEBUG
                fatalError("Unresolved error \(error), \(error.userInfo)")
                #endif

            }
        })
        return container
    }()

    // MARK: - Core Data Saving support
    func saveContext () {
        let context = persistentContainer.viewContext
        managedContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                Crashlytics.sharedInstance().recordError(error)
            }
        }
    }

发生崩溃的函数:

调用.swift:

let callEntity = NSEntityDescription.entity(forEntityName: "Call", in: managedContext)!

  static func upsertCall(call: Call?) {
        if(call == nil){
            return
        }

        //validation here..
        //..

        do {
            managedContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
            try managedContext.save()
        } catch {
            let nserror = error as NSError
            NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
            Crashlytics.sharedInstance().recordError(error)
        }
    }

跑步 - 斯威夫特 5 - Xcode 10.2

【问题讨论】:

  • 您好,您的问题解决了吗。

标签: swift iphone core-data


【解决方案1】:

这是一个 VOIP 应用程序,获取后台 CallKit 推送,并且在某些情况下,将它们写入 CoreDate DB。我怀疑这就是导致应用程序崩溃的原因,但我在网上找不到任何对它的引用。

尝试在本地重现此问题但没有成功,可能是因为在您第一次解锁手机之前无法使用 Xcode 进行调试。

前段时间我遇到过类似的问题,即当没有对 DB 文件的访问权限时运行应用程序。

我已使用以下设置来调试此问题:

  1. 启用(实现)日志记录到文件(例如使用 CocoaLumberjack,但任何日志记录都可以)。 确保文件访问权限设置为NSFileProtectionNone,以便随时可以写入!
  2. 尽可能记录有问题的代码以及与应用程序生命周期相关的所有应用程序委托回调。
  3. 在设备上安装应用程序。 必须启用密码和锁定

现在使用上面的设置,有多种情况会触发这个问题:

  1. 重启手机,不要输入密码,让它躺下,旧的 iOS 过去常常在几个小时/几天后生成应用程序,只是为了执行后台提取(如果已设置)。
  2. 重启手机,不要输入密码,触发远程推送通知或voip通话。

在分析日志后的两种情况下,很明显应用程序在后台被唤醒,但文件保护尚未解除(因为没有输入密码)。

现在,老实说,我不知道上述问题是否还会重现,但您的问题似乎非常相似。

那么 - 解决方案呢?

此问题会影响文件和钥匙串访问。我已经看到许多应用程序没有正确实现(结果:用户被随机注销,因为应用程序无法访问钥匙串来查询身份验证令牌)和经常共享的解决方案是通过指定 kSecAttrAccessibleAlways 来解除对文件/钥匙串的所有访问权限用于钥匙串条目或上面提到的NSFileProtectionNone 用于文件。

我相信虽然这样可行,但从安全角度来看,这通常是个坏主意。

可以做的是推迟应用服务的启动和所有设置,直到可以访问文件。如果应用程序应该在后台写入 DB,请将文件权限设置为至少 NSFileProtectionCompleteUntilFirstUserAuthentication 并仅在可以写入访问权限时打开 DB。检查isProtectedDataAvailable 不是一个很好的解决方案 - 根据我的经验,如果屏幕被锁定并设置了密码,则始终返回 false,并且不考虑个人文件访问权限。

【讨论】:

  • 我同意,这个 isProtectedDataAvailable API 并不是很有用……我再次对 iOS SDK 的所有这些愚蠢的 API 限制感到沮丧……
  • 现在我必须跳很多圈才能优雅地捕捉/处理我的 Swift 库中的“设备锁定”致命错误。因为客户对崩溃很生气......但同时希望在用户通过身份验证之前保护数据
  • @kas-kad 你能在这里分享崩溃处理代码sn-p吗?
  • @AnkitaPundir 我使用 SwiftTryCatch 来捕获异常并且不让应用崩溃
【解决方案2】:

我在崩溃中看到了类似的错误: CoreData:-[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_loc ... + 52

我的理解是应用程序正在做某事,但不允许访问核心数据。就我而言,是在将数据从通知中保存到核心数据时。

我将此检查添加到保存到核心数据的方法中:

if !UIApplication.shared.isProtectedDataAvailable {
            return
        }

【讨论】:

    猜你喜欢
    • 2013-03-07
    • 2020-05-30
    • 2012-08-18
    • 1970-01-01
    • 2016-03-15
    • 2016-02-04
    • 1970-01-01
    • 2014-10-15
    • 2023-03-16
    相关资源
    最近更新 更多