Xcode报错:Can only invoke this method on the main queue
Xcode报错:Can only invoke this method on the main queue

Xcode报错:Can only invoke this method on the main queue

问题复现

在Xcode预览中,发现点击“统计”模块后,发生报错。

具体的报错提示为:

Can only invoke this method on the main queue

报错翻译为:只能在主队列上调用此方法

这意味着,我在的代码在非主线程(例如backgroundContext)中调用了只能在主线程中使用的 API。

因为我的统计数据量非常大,频繁调用Core Data查询,因此需要大概50秒的时间,所以我把统计放到backgroundContext中执行。

排查定位

怀疑是backgroundContext导致的问题,通过排查定位发现,当代码中调用appStorage这个管理对象时,因为appStorage是SwiftUI 的 @EnvironmentObject传递的,属于UI环境下的数据,只能在主线程读取,在后台线程访问就会崩溃。

// 轮训汇率的所有日期
private func CalculatingHistoricalHighs() {
    backgroundContext.perform {
        CalculateForeignCurrencyAmounts(date: rateDate,userCurrencies: UserCurrency)
    }
}

func CalculateForeignCurrencyAmounts(date: Date, userCurrencies: [UserForeignCurrency]) {
    do {
        // appStorage是外部定义的管理对象,只能在主现场读取
        if calculateCount >= appStorage.historicalHigh && calculateCount > 0 {
            appStorage.historicalHigh = calculateCount
            appStorage.historicalTime = date.timeIntervalSince1970
        }
    } catch {
        print("backgroundContext发生了报错")
    }
}

解决方案

当需要在主线程操作时,需要在DispatchQueue.main.async中调用:

DispatchQueue.main.async {
    if calculateCount >= appStorage.historicalHigh && calculateCount > 0 {
        appStorage.historicalHigh = calculateCount
        appStorage.historicalTime = date.timeIntervalSince1970
    }
}

预览恢复正常。

总结

当代码在非主线程中(例如backgroundContext)中调用时,涉及@EnvironmentObject等SwiftUI代码时,都需要在主线程中调用。

解决方法就是使用DispatchQueue.main.async代码块包裹需要主线程调用的代码。

最后,如果预览仍然报错,需要使用 “Clean Build Folder” 功能,清理构建文件夹,重新构建预览代码。

相关文章

1、Core Data NSManagedObjectContext的后台上下文backgroundContext:https://fangjunyu.com/2025/03/31/core-data-nsmanagedobjectcontext%e7%9a%84%e5%90%8e%e5%8f%b0%e4%b8%8a%e4%b8%8b%e6%96%87backgroundcontext/

2、Swift主线程:https://fangjunyu.com/2024/12/25/swift%e4%b8%bb%e7%ba%bf%e7%a8%8b/

3、Swift中的线程模型:https://fangjunyu.com/2024/12/25/swift%e4%b8%ad%e7%9a%84%e7%ba%bf%e7%a8%8b%e6%a8%a1%e5%9e%8b/

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注