如何以线程安全方式监听UIPasteboard?Swift 6适配问题
Swift 6下@Observable类修改状态的解决方案
Swift 6中@Observable会将类隐式转换为actor隔离类型,状态修改必须在对应actor的隔离上下文内执行。原代码中通知闭包未正确绑定隔离上下文,导致无法修改images属性,以下是两种可行方案:
方案一:异步机制(推荐,适配Swift 6并发模型)
通过Task自动切换到@Observable类的actor隔离上下文,安全修改状态,同时避免循环引用:
@Observable final class ImageClipboard { var images: [SelectableImage] = [] init() { NotificationCenter.default.addObserver(forName: UIPasteboard.changedNotification, object: nil, queue: .main) { [weak self] _ in guard let self = self, let pasteboardImages = UIPasteboard.general.images else { return } let newImages = pasteboardImages.map(SelectableImage.init) // 异步进入actor上下文修改状态 Task { self.images.append(contentsOf: newImages) } } } }
这种方式无需硬编码主线程依赖,适配@Observable类默认的actor隔离规则,后续代码变更时兼容性更好。
方案二:同步机制(显式绑定主线程)
若确定所有操作都在主线程执行,可将类显式标记为@MainActor,此时通知闭包运行在主线程(已指定queue: .main),可直接修改状态:
@MainActor @Observable final class ImageClipboard { var images: [SelectableImage] = [] init() { NotificationCenter.default.addObserver(forName: UIPasteboard.changedNotification, object: nil, queue: .main) { [weak self] _ in guard let self = self, let pasteboardImages = UIPasteboard.general.images else { return } let newImages = pasteboardImages.map(SelectableImage.init) // 直接修改状态,当前已在MainActor上下文 self.images.append(contentsOf: newImages) } } }
该方案更简洁,适合UI相关的剪贴板监听场景,所有状态变更都在主线程完成,避免跨线程UI同步问题。
通用注意事项
- 必须使用
[weak self]捕获,避免NotificationCenter持有闭包导致的循环引用,确保类实例能正常释放。 - 处理剪贴板内容时增加空值判断,避免
UIPasteboard.general.images为nil时引发异常。
内容的提问来源于stack exchange,提问作者Nitesh
相关产品推荐
相关产品推荐

