Issue #686

I now use Core Data more often now. Here is how I usually use it, for example in Push Hero

From iOS 10 and macOS 10.12, NSPersistentContainer that simplifies Core Data setup quite a lot. I usually use 1 NSPersistentContainer and its viewContext together with newBackgroundContext attached to that NSPersistentContainer

In Core Data, each context has a queue, except for viewContext using the DispatchQueue.main, and each NSManagedObject retrieved from 1 context is supposed to use within that context queue only, except for objectId property.

Although NSManagedObject subclasses from NSObject, it has a lot of other constraints that we need to be aware of. So it’s safe to treat Core Data as a cache layer, and use our own model on top of it. I usually perform operations on background context to avoid main thread blocking, and automaticallyMergesChangesFromParent handles merge changes automatically for us.

extension SendHistoryItem {
    func toCoreData(context: NSManagedObjectContext) {
        context.perform {
            let cd = CDSendHistoryItem(context: context)
        }
    }
}

extension CDSendHistoryItem {
    func toModel() throws -> SendHistoryItem {
        
    }
}

final class CoreDataManager {
    private var backgroundContext: NSManagedObjectContext?

    init() {
        self.backgroundContext = self.persistentContainer.newBackgroundContext()
    }

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "PushHero")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error {
                print(error)
            }
        })
        return container
    }()

    func load(request: NSFetchRequest<CDSendHistoryItem>, completion: @escaping ([SendHistoryItem]) -> Void) {
        guard let context = CoreDataManager.shared.backgroundContext else { return }
        context.perform {
            do {
                let cdItems = try request.execute()
                let items = cdItems.compactMap({ try? $0.toModel() })
                completion(items)
            } catch {
                completion([])
            }
        }
    }

    func save(items: [SendHistoryItem]) {
        guard let context = backgroundContext else {
            return
        }

        context.perform {
            items.forEach {
                let _ = $0.toCoreData(context: context)
            }
            do {
                try context.save()
            } catch {
                print(error)
            }
        }
    }
}

Read more


Updated at 2020-10-25 20:58:07