Home > Software design >  Why my core data setup didnt finish to setup on time?
Why my core data setup didnt finish to setup on time?

Time:01-19

the following issue ONLY sometimes APPEAR, and never on my device. It happens a lot of times to users of my app.

enter image description here

I tried to regenerate that issue on my own device, and I simply commented it out where I setup my core data stack. And the error is the following:

enter image description here

In my opinion it is the same, and the reason why it happens on production is that... core data stack didnt finish to setup before it is used in the app. Am I right?

Look at below code. This is how I setup my Core Data:

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)
            }
        }
    }
}

And this is simply called here:

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

CodePudding user response:

As CoreDataManager is a singleton it makes no sense to implement an extra setup method – which will be called only once anyway – and perform nil checks. A better way is to implement init and do all the setup stuff there.

All properties in a Core Data stack – especially in a singleton – are supposed to be non-optional. Properties which depend on each other can be initialised lazily.

And NSPersistentStoreCoordinator is outdated. Apple introduced NSPersistentContainer many years ago.

A contemporary implementation of a Core Data stack is something like this, I commented out some lines which threw compile errors

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
    }()
}
  • Related