Swift 6并发:如何在LogManager初始化时同步调用MainActor隔离方法?
解决方案
要确保系统信息作为第一条日志存入数组,同时不将整个LogManager置于MainActor隔离,推荐采用预占位+异步替换的方式,具体实现如下:
修改后的LogManager代码
@objc public final class LogManager: NSObject, @unchecked Sendable { static let sharedInstance = LogManager() private var _logs: [String] = [] private let serialQueue = DispatchQueue(label: "LoggingSerialQueue") private override init() { super.init() // 先添加占位符,抢占第一条日志的位置 serialQueue.sync { _logs.append("系统信息加载中...") } // 异步在MainActor获取系统信息,再替换占位符 Task { @MainActor in let systemInfo = SysInfo.sysInfo() serialQueue.sync { // 确保数组非空时替换第一个元素,避免边界问题 if !_logs.isEmpty { _logs[0] = systemInfo } else { _logs.append(systemInfo) } print("****LogManager**** \(systemInfo)") } } } func log(_ log: String) { serialQueue.sync { self._logs.append(log) print("****LogManager**** \(log)") } } // 可选:提供线程安全的日志读取方法 var logs: [String] { serialQueue.sync { _logs } } }
方案说明
- 预占位保证顺序:初始化时先通过串行队列添加占位字符串,后续所有
log调用的内容都会排在它之后,从根源上确保系统信息最终是第一条日志。 - 异步获取不阻塞:通过
Task在MainActor安全获取系统信息,全程不会阻塞LogManager的初始化流程,也不影响多线程调用log的逻辑。 - 线程安全延续:所有对
_logs数组的操作都通过串行队列同步执行,延续了原代码的线程安全设计,避免多线程竞争问题。
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

