You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

标记@MainActor的update方法刷新collectionView仍崩溃,原因何在?

问题原因与解决方法

核心问题

PHPhotoLibraryChangeObserver的photoLibraryDidChange回调是在后台串行队列触发的,并非主线程。你虽然给update标记了@MainActor,但直接在后台线程同步调用这个方法时,Swift的Actor机制并不会自动切换到主线程执行代码——因为@MainActor的调度逻辑需要结合**异步上下文(async/await)**或者显式的MainActor上下文切换才能生效,同步调用无法触发线程切换,导致collectionView.reloadData()仍在后台线程执行,最终触发UI操作的崩溃。

解决方法

以下几种方式都能解决问题,选一种适合你的即可:

方法1:用Task显式切换到MainActor上下文调用update

extension PhotosCollectionViewController: PHPhotoLibraryChangeObserver {
    func photoLibraryDidChange(_ changeInstance: PHChange) {
        Task { @MainActor in
            update()
        }
    }
    
    @MainActor private func update() {
        collectionView.reloadData()
    }
}

方法2:将update改为async方法,通过await调用

extension PhotosCollectionViewController: PHPhotoLibraryChangeObserver {
    func photoLibraryDidChange(_ changeInstance: PHChange) {
        Task {
            await update()
        }
    }
    
    @MainActor private func update() async {
        collectionView.reloadData()
    }
}

方法3:直接在update内用MainActor.run(兼容旧写法)

如果不想改动调用逻辑,也可以在update方法内显式指定UI操作在主线程执行:

@MainActor private func update() {
    MainActor.run {
        collectionView.reloadData()
    }
}

补充说明

GCD的DispatchQueue.main.async之所以能正常工作,是因为它直接将UI操作任务派发到主线程队列;而@MainActor的作用是标记代码属于MainActor的执行上下文,只有在异步调用或者显式切换到MainActor上下文时,才能确保代码在主线程运行,同步调用无法触发这个调度逻辑。

内容的提问来源于stack exchange,提问作者Karina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:25:25