Swift 5.5:主线程处理通知时如何正确访问通知对象?
解决Notification在@Sendable闭包中的捕获警告问题
问题代码
class ViewController : NSViewController { override func loadView() { NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification, object: view, queue: .main) { [self] n in DispatchQueue.main.async { self.resizeSubviews(animate: false, sender: n.object) // <- 此处触发警告 } } } func resizeSubviews(animate: Bool, sender: Any?) { } }
触发的警告
Capture of 'n' with non-sendable type 'Notification' in a `@Sendable` closure
问题原因
通知处理闭包本身是@Sendable类型,内层的DispatchQueue.main.async闭包也会被推断为@Sendable。由于Notification当前未遵循Sendable协议,将其捕获进内层@Sendable闭包时,编译器会抛出线程安全相关警告。
解决方案
方案1:提前提取所需属性(推荐)
在进入内层闭包前,先提取需要的n.object,让内层闭包仅捕获该属性而非整个Notification实例,从根源避免捕获非Sendable类型:
class ViewController : NSViewController { override func loadView() { NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification, object: view, queue: .main) { [self] n in // 提前提取属性,避免捕获整个Notification let targetSender = n.object DispatchQueue.main.async { self.resizeSubviews(animate: false, sender: targetSender) } } } func resizeSubviews(animate: Bool, sender: Any?) { } }
方案2:标记内层闭包为@unchecked Sendable(谨慎使用)
如果确实需要访问整个Notification实例,且能确认当前场景无线程安全风险(比如所有操作都在主线程),可以给内层闭包添加@unchecked Sendable标记,绕过编译器警告:
class ViewController : NSViewController { override func loadView() { NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification, object: view, queue: .main) { [self] n in DispatchQueue.main.async { @unchecked Sendable in self.resizeSubviews(animate: false, sender: n.object) } } } func resizeSubviews(animate: Bool, sender: Any?) { } }
注意:@unchecked Sendable会关闭编译器的Sendable检查,必须确保代码逻辑不会引发线程安全问题才能使用。
内容的提问来源于stack exchange,提问作者C. Ocoa
相关产品推荐
相关产品推荐

