已用DispatchQueue.main.async仍收到后台线程发布变更警告的问题
问题排查与解决方案
问题根源
你看到的紫色警告并非来自HTTPHandler的statusMsg修改(你已经正确用DispatchQueue.main.async包裹了这些操作),而是来自**XFile对象的属性修改在后台线程执行**:
在asyncCall方法中,你直接在后台线程执行了xFile.fileStage = .converting,如果fileStage是XFile类的@Published属性,这会触发XFile的状态发布操作,而该操作发生在后台线程,完全符合警告描述的场景。
此外,URLSession.data(for:)的异步回调恢复线程不一定是主线程,任何未明确指定主线程的ObservableObject属性修改,都可能触发类似警告。
修复方案
1. 修正xFile属性的线程问题
将xFile.fileStage的修改包裹到主线程执行,同时可以合并同一块的statusMsg修改,减少冗余:
// 替换原有的xFile.fileStage = .converting和单独的statusMsg修改 DispatchQueue.main.async { [self, xFile] in xFile.fileStage = .converting statusMsg = "Converting" }
2. 给HTTPHandler添加全局线程安全保障(可选,更优雅)
如果不想每次修改属性都手动写DispatchQueue.main.async,可以利用Combine的receive(on:)操作符,强制所有@Published属性的发布都在主线程:
class HTTPHandler: NSObject, ObservableObject { @Published var statusMsg = "" @Published var stage = FileStage.makeTicket @Published var errorMsg = "" init() { super.init() // 强制所有属性的发布切换到主线程 $statusMsg.receive(on: DispatchQueue.main).assign(to: &$statusMsg) $stage.receive(on: DispatchQueue.main).assign(to: &$stage) $errorMsg.receive(on: DispatchQueue.main).assign(to: &$errorMsg) } func asyncCall(request: URLRequest, xFile: XFile) async -> Int { // 此时可以移除所有DispatchQueue.main.async包裹,直接修改属性即可 do { let (data, response) = try await URLSession.shared.data(for: request) guard let httpResponse = response as? HTTPURLResponse else { statusMsg = "Unknown Error 1" return 1 } if httpResponse.statusCode == 200 { if xFile.jsonAndXFile(data: data) { if xFile.hData.status == "SUCCESS" && xFile.hData.returnvalue == "SSFILEUPLOADED" { DispatchQueue.main.async { xFile.fileStage = .converting } statusMsg = "Converting" } else if xFile.hData.status == "SUCCESS" && xFile.hData.returnvalue == "SSCONVERTING" { statusMsg = String(format: "Converting %@%%", xFile.hData.message) } else if xFile.hData.status == "SUCCESS" && xFile.hData.returnvalue == "SSSTAGE1" { statusMsg = String(format: "Converting %@%%", xFile.hData.message) } } else { statusMsg = "JSON err" return 4 } } else { statusMsg = String(format: "URL error: %d", httpResponse.statusCode) return 3 } } catch { statusMsg = "async error: 2" return 2 } return 0 } }
3. 检查XFile类的其他异步操作
确认XFile类中所有修改@Published属性的操作,都确保在主线程执行,避免遗漏其他触发警告的场景。
内容的提问来源于stack exchange,提问作者Bartender1382
相关产品推荐
相关产品推荐

