如何将PHPhotoLibraryChangeObserver迁移到Swift 6并适配严格并发检查?
Swift 6 下 PHPhotoLibraryChangeObserver 适配崩溃问题解决
问题背景
以下代码在Swift 6中触发编译错误:
extension AssetGridViewController: PHPhotoLibraryChangeObserver { func photoLibraryDidChange(_ changeInstance: PHChange) { Task { @MainActor in guard let changes = changeInstance.changeDetails(for: fetchResult) else { return } fetchResult = changes.fetchResultAfterChanges } } }
AssetGridViewController为普通UIViewController实例,编译错误提示:
Main actor-isolated instance method 'photoLibraryDidChange' cannot be used to satisfy nonisolated protocol requirement
按照错误提示的两种修复方案操作后,均会触发运行时崩溃:EXC_BREAKPOINT (code=1, subcode=0x105b7c400):
- 方案1:给方法添加
nonisolated修饰 - 方案2:给协议扩展添加
@preconcurrency修饰
解决方案
问题根源在于PHPhotoLibraryChangeObserver的回调方法在非主线程执行,直接使用@MainActor修饰Task会捕获当前非隔离上下文与Main Actor的冲突。正确实现方式如下:
extension AssetGridViewController: PHPhotoLibraryChangeObserver { nonisolated func photoLibraryDidChange(_ changeInstance: PHChange) { Task { [weak self] in guard let self = self, let changes = changeInstance.changeDetails(for: self.fetchResult) else { return } await MainActor.run { self.fetchResult = changes.fetchResultAfterChanges // 在此添加UI更新逻辑,如刷新集合视图 } } } }
核心要点
nonisolated修饰方法:满足协议的非隔离要求,消除编译错误,明确该方法不绑定Main Actor。- 弱引用
self:避免Task持有强引用导致内存泄漏。 await MainActor.run切换线程:在Main Actor上下文内更新实例属性和UI,既保证并发安全,又符合UI操作必须在主线程的要求。
此实现既能通过Swift 6的并发安全检查,又不会触发运行时崩溃。
内容的提问来源于stack exchange,提问作者Andrés Pizá Bückmann
相关产品推荐
相关产品推荐

