Concurrency MainActor崩溃排查:root.user-initiated-qos.cooperative
崩溃原因分析与修复方案
崩溃信息
Crashed: com.apple.root.user-initiated-qos.cooperative
触发代码
@Published var thing: Thing? func start() { Task { @MainActor in await getThing() } } func getThing() async { self.thing = await foo.fetchThing() }
问题根源
你误以为start()里的@MainActor会让getThing()全程保持MainActor上下文,但实际并非如此:
- 虽然
getThing()是在MainActor的上下文中被调用,但执行到await foo.fetchThing()时,当前任务会被挂起; - 异步操作完成后,系统会从全局线程池中选取一个可用线程恢复任务执行,此时不再处于MainActor线程;
- 而
@Published属性的赋值必须在MainActor(主线程)上执行,非主线程赋值就会触发崩溃。
修复方案
有两种可靠的修复方式:
方式一:给getThing()标注@MainActor
强制整个方法的执行上下文绑定MainActor,确保赋值操作在主线程完成:
@Published var thing: Thing? func start() { Task { @MainActor in await getThing() } } @MainActor func getThing() async { self.thing = await foo.fetchThing() }
方式二:显式切换到MainActor执行赋值
在获取到数据后,通过MainActor.run将赋值操作切回主线程:
@Published var thing: Thing? func start() { Task { @MainActor in await getThing() } } func getThing() async { let fetchedThing = await foo.fetchThing() await MainActor.run { self.thing = fetchedThing } }
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

