如何执行CoreData上下文.从后台线程计数?

2022-01-27 14:09:27 标签 iosswiftcore-data

目前,以下是我关于CoreData的实现。

class CoreDataStack {
    static let INSTANCE = CoreDataStack()
    
    private init() {
    }
    
    private(set) lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "xxx")
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // This is a serious fatal error. We will just simply terminate the app, rather than using error_log.
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        
        // So that when backgroundContext write to persistent store, container.viewContext will retrieve update from
        // persistent store.
        container.viewContext.automaticallyMergesChangesFromParent = true
        
        return container
    }()
    
    private(set) lazy var backgroundContext: NSManagedObjectContext = {
        let backgroundContext = persistentContainer.newBackgroundContext()
        backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        return backgroundContext
    }()
}
class NSAttachmentRepository {
    static let INSTANCE = NSAttachmentRepository()
    
    private init() {
    }
    
    func isExist(_ name: String) -> Bool {
        let coreDataStack = CoreDataStack.INSTANCE
        let viewContext = coreDataStack.persistentContainer.viewContext
        
        let fetchRequest = NSFetchRequest<NSAttachment>(entityName: "NSAttachment")
        fetchRequest.fetchLimit =  1
        fetchRequest.predicate = NSPredicate(format: "name == %@", name)
        do {
            let count = try viewContext.count(for: fetchRequest)
            if count > 0 {
                return true
            }
        } catch {
            error_log(error)
        }
        
        return false
    }
}

我处理核心数据的策略是

为了从主线程(UI线程)执行非阻塞的写调用,我将使用CoreDataStack.INSTANCE.backgroundContext

为了执行阻塞读调用从主线程(UI线程),我将使用CoreDataStack.INSTANCE.persistentContainer.viewContext

这个工作一直很好,直到我需要执行以下操作

从后台线程(非UI线程)执行阻塞读调用

我们需要在PHPickerViewControllerDelegate的loadFileRepresentation回调中运行代码。如果我们使用Thread来检查。isMainThread(返回false)在loadFileRepresentation回调中,它是在后台线程中执行的。

当我执行调用NSAttachmentRepository。INSTANCE。isExist(name)在函数中线程。isMainThread是假的,我将得到以下崩溃

(NSManagedObjectContext CoreData ' +

Multithreading_Violation_AllThatIsLeftToUsIsHonor]:

我试图通过修改代码从使用coreDataStack。persistentContainer。viewContext到coreDataStack。backgroundContext来“修复”这个问题

func isExist(_ name: String) -> Bool {
    let coreDataStack = CoreDataStack.INSTANCE
    ////let viewContext = coreDataStack.persistentContainer.viewContext
    let backgroundContext = coreDataStack.backgroundContext
    
    let fetchRequest = NSFetchRequest<NSAttachment>(entityName: "NSAttachment")
    fetchRequest.fetchLimit =  1
    fetchRequest.predicate = NSPredicate(format: "name == %@", name)
    do {
        ////let count = try viewContext.count(for: fetchRequest)
        let count = try backgroundContext.count(for: fetchRequest)
        if count > 0 {
            return true
        }
    } catch {
        error_log(error)
    }
    
    return false
}

然而,我仍然得到同样的崩溃错误。

你有任何想法我可以执行CoreData上下文。从后台线程计数?

###仅仅使用背景背景是不够的。您需要在它自己的队列上使用该上下文。你检查你不是在主队列上运行,但你可以在任何队列上,而后台上下文只在其中一个上工作。当你在错误的队列上使用它时,你看到的错误消息是Core Data说的。

任何时候你使用backgroundContext你需要包装代码在一个调用执行或performAndWait,以确保你的代码运行在后台上下文的队列。因为你的isExist函数是同步的,它需要使用performAndWait,这样它可以在返回之前得到一个结果。

###感谢汤姆·哈灵顿的提示

下面是关于如何处理线程问题的代码片段。

func isExist(_ name: String) -> Bool {
    let coreDataStack = CoreDataStack.INSTANCE
    let viewContext = coreDataStack.persistentContainer.viewContext
    var result = false
    
    viewContext.performAndWait {
        let fetchRequest = NSFetchRequest<NSAttachment>(entityName: "NSAttachment")
        fetchRequest.fetchLimit =  1
        fetchRequest.predicate = NSPredicate(format: "name == %@", name)
        do {
            let count = try viewContext.count(for: fetchRequest)
            if count > 0 {
                result = true
            } else {
                result = false
            }
        } catch {
            error_log(error)
        }
    }
    return result
}
阅读全文

▼ 版权说明

相关文章也很精彩
推荐内容
更多标签
相关热门
全站排行
随便看看

错说 cuoshuo.com —— 程序员的报错记录

部分内容根据CC版权协议转载;网站内容仅供参考,生产环境使用务必查阅官方文档

辽ICP备19011660号-5

×

扫码关注公众号:职场神器
发送: 1
获取永久解锁本站全部文章的验证码