【问题标题】:Why my core data setup didn't finish to setup on time?为什么我的核心数据设置没有按时完成设置?
【发布时间】:2023-02-11 17:35:46
【问题描述】:

以下问题只是有时出现,而且从未出现在我的设备上。我的应用程序的用户经常会遇到这种情况。

我试图在我自己的设备上重新生成该问题,我只是在我设置核心数据堆栈的地方将其注释掉。错误如下:

在我看来它是一样的,它在生产中发生的原因是......核心数据堆栈在应用程序中使用之前没有完成设置。我对吗?

看下面的代码。这就是我设置核心数据的方式:

class CoreDataManager {
    static var shared = CoreDataManager()
    private var coordinator: NSPersistentStoreCoordinator?
    var rootContext: NSManagedObjectContext?
    var defaultContext: NSManagedObjectContext?
    func setup() {
    
        guard coordinator == nil && defaultContext == nil else {
            return
        }
        if let managedObjectModel = NSManagedObjectModel.defaultModel {
            coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
        
            var storePath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: SharedGroupName)
        
            storePath = storePath!.appendingPathComponent("FieldService.sqlite")
        
            let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
        
            do {
                try coordinator?.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storePath, options: options)
                rootContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
                rootContext?.persistentStoreCoordinator = coordinator
                rootContext?.obtainPermanentIdsBeforeSaving()
                rootContext?.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
                defaultContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
                defaultContext?.setupDefaultContext()
                defaultContext?.obtainPermanentIdsBeforeSaving()
                defaultContext?.parent = rootContext
            } catch let error as NSError {
                print("SUPER ERROR>>>>>>>>>")
                print(error)
            }
        }
    }
}

这在这里简单地称为:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    CoreDataManager.shared.setup()
    // another stuff
}

Vadian 的回答问题:

【问题讨论】:

  • 只是不要完全在您的代码中使用强制解包。这是一个众所周知的崩溃秘诀。使用例如if let x = ... {...}
  • 好的,我明白了,但这不是我的问题。它不应该是 NIL 为什么会这样?

标签: ios swift core-data


【解决方案1】:

由于 CoreDataManager 是一个单例,因此实现额外的 setup 方法(无论如何只会调用一次)并执行 nil 检查是没有意义的。更好的方法是实现 init 并在那里进行所有设置。

核心数据堆栈中的所有属性——尤其是在单例中——都应该是非可选的。相互依赖的属性可以延迟初始化。

NSPersistentStoreCoordinator 已经过时了。 Apple 多年前推出了NSPersistentContainer

Core Data 堆栈的当代实现是这样的,我注释掉了一些引发编译错误的行

class CoreDataManager {
    static let shared = CoreDataManager()
    
    private let container: NSPersistentContainer
    
    init() {
        container = NSPersistentContainer(name: "FieldService")
        let storedescriptionOptions = NSPersistentStoreDescription()
        storedescriptionOptions.setOption(true as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption)
        storedescriptionOptions.setOption(true as NSNumber, forKey: NSInferMappingModelAutomaticallyOption)
        container.persistentStoreDescriptions = [
            NSPersistentStoreDescription(url: FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: SharedGroupName)!.appendingPathComponent("FieldService.sqlite")),
            storedescriptionOptions
        ]
        container.loadPersistentStores { _, error in
            if let error { fatalError(error.localizedDescription) }
        }
    }
  
    lazy var rootContext : NSManagedObjectContext = {
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        context.persistentStoreCoordinator = container.persistentStoreCoordinator
        // context.obtainPermanentIdsBeforeSaving()
        context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
        return context
    }()
    
    lazy var defaultContext : NSManagedObjectContext = {
        let context = self.container.viewContext
        // context.setupDefaultContext()
        // context.obtainPermanentIdsBeforeSaving()
        context.parent = rootContext
        return context
    }()
}

【讨论】:

  • 哇,您认为替换我的代码更好吗?;)如果是,您就是天才;)谢谢。它看起来很聪明而且非常非常好。我稍后会检查它,现在我还是投票赞成它;)
  • 你好,我已经实现了你的想法,但是在从核心数据中获取对象时遇到了问题:*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Context already has a coordinator; cannot replace.' 我已经编辑了一个问题来显示错误。
  • 不是应该互相替换吗? defaultContext 应该是 rootContext?
  • 我只是试图将您的代码重构为更现代的 API。是的,通常主线程上提供的上下文也是主上下文。由您来清理它。
  • 好吧,我设法让它工作了;)没关系……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-07
  • 2011-02-14
  • 2011-10-21
相关资源
最近更新 更多