如何在后台上下文的 SwiftUI 应用程序中使用 CoreData 以免阻塞主线程进行繁重的操作

发布于 2025-01-10 01:47:06 字数 2497 浏览 2 评论 0原文

我有一个使用核心数据的 swiftUI 应用程序。

我已经设置了一个 CoreDataManager,并且我想使用 coreData 执行一些操作,这些操作会阻塞主线程,因此我想在后台上下文中执行它们。

获取后台上下文,

我知道我可以使用CoreDataManager.shared.persistentContainer.newBackgroundContext()

但我相信每次都会得到不同的上下文,如果从不同的地方同时完成,可能会导致一些合并问题。

我还可以看到共享 CoreDataManager 上有一个 PerformBackgroundTask 函数,但我不确定在该块中使用哪个上下文。

只是想知道在不阻塞主线程的情况下使用核心数据的标准做法是什么。这是我的堆栈:

class CoreDataManager {
    
    // MARK: - Properties
    
    static let shared = CoreDataManager()
    
    var persistentContainer: NSPersistentContainer!
    
    var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    
    // MARK: - Init Methods
    
    private init() {
        NotificationCenter.default.addObserver(self, selector: #selector(backgroundContextDidSave(notification:)), name: .NSManagedObjectContextDidSave, object: nil)
    }
    
    // MARK: - Helper Methods
    
    func prepare() {
        let groupName = Theme.appGroup
        let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName)!.appendingPathComponent(AHTheme.databaseIdentifier)
        persistentContainer = NSPersistentContainer(name: Theme.appName)
        persistentContainer.persistentStoreDescriptions = [NSPersistentStoreDescription(url: url)]
        persistentContainer.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        context.automaticallyMergesChangesFromParent = true
    }
    
    @objc func backgroundContextDidSave(notification: Notification) {
        guard let notificationContext = notification.object as? NSManagedObjectContext else { return }
        guard notificationContext !== context else {
            return
        }
        context.perform {
            self.context.mergeChanges(fromContextDidSave: notification)
        }
    }
    
    func performBackgroundTask(block: @escaping (NSManagedObjectContext) -> Void) {
        persistentContainer.performBackgroundTask(block)
    }
    
    func saveContext() {
        do {
            if persistentContainer.viewContext.hasChanges {
                try persistentContainer.viewContext.save()
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}

I have a swiftUI app using core data.

I have setup a CoreDataManager and I have some operations I want to perform using coreData that would block the main thread so I want to perform them on a background context.

I know that I can get a background context using:

CoreDataManager.shared.persistentContainer.newBackgroundContext()

but I believe this get's a different context each time which may cause some merging issues if done at the same time from different places.

I also can see there is a performBackgroundTask function on the shared CoreDataManager but I'm not sure which context to use in that block.

Just wondering what is the standard practice for using core data without blocking main thread. This is my stack:

class CoreDataManager {
    
    // MARK: - Properties
    
    static let shared = CoreDataManager()
    
    var persistentContainer: NSPersistentContainer!
    
    var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    
    // MARK: - Init Methods
    
    private init() {
        NotificationCenter.default.addObserver(self, selector: #selector(backgroundContextDidSave(notification:)), name: .NSManagedObjectContextDidSave, object: nil)
    }
    
    // MARK: - Helper Methods
    
    func prepare() {
        let groupName = Theme.appGroup
        let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName)!.appendingPathComponent(AHTheme.databaseIdentifier)
        persistentContainer = NSPersistentContainer(name: Theme.appName)
        persistentContainer.persistentStoreDescriptions = [NSPersistentStoreDescription(url: url)]
        persistentContainer.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        context.automaticallyMergesChangesFromParent = true
    }
    
    @objc func backgroundContextDidSave(notification: Notification) {
        guard let notificationContext = notification.object as? NSManagedObjectContext else { return }
        guard notificationContext !== context else {
            return
        }
        context.perform {
            self.context.mergeChanges(fromContextDidSave: notification)
        }
    }
    
    func performBackgroundTask(block: @escaping (NSManagedObjectContext) -> Void) {
        persistentContainer.performBackgroundTask(block)
    }
    
    func saveContext() {
        do {
            if persistentContainer.viewContext.hasChanges {
                try persistentContainer.viewContext.save()
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文