创建用于 AppKit 的
AttributedString
时,我收到一条警告,指出 NSFont
不是 Sendable
:
var container = AttributeContainer()
container.appKit.foregroundColor = .red
container.appKit.font = .systemFont(ofSize: mySize)
// ^ Conformance of 'NSFont' to 'Sendable' is unavailable
警告是正确的,
NSFont
不是Sendable
,那么有没有办法在不关闭并发警告的情况下完成此任务?在审核 Sendable
一致性方面,AppKit 远远落后于 SwiftUI 和 UIKit,但我对此无能为力。将 Foundation
的导入标记为 @preconcurrency
没有任何效果。快速测试项目表明字体设置正确并且可以在 NSTextView
中使用。我只是不想一直盯着这些警告,直到苹果开始改进 AppKit(从历史上看,可能需要相当长的时间)。
我建议您,尽管 NSFont 不是可发送的,但这并不一定意味着跨线程使用它不安全。截至 iOS SDK 的当前状态,它还没有经过正式的线程安全审核(我认为——还没有检查文档)。
您正确地观察到 AppKit 在采用新的 Swift 并发功能方面落后于 SwiftUI 和 UIKit。必须了解 Sendable 协议是一种编译时检查,它不会使类型成为线程安全的;它仅表明该类型在设计时考虑了线程安全。
当使用像 NSFont 这样不可发送的类型时,以注意并发性的方式使用它们是至关重要的。大多数情况下,这意味着仅在主线程上使用它们,因为 AppKit 和 UIKit 并非设计为线程安全的。
要抑制有关 NSFont 不可发送的警告,您可以在 NSFont 周围创建一个包装器,以断言其在主线程上的使用情况。这是一个例子:
struct MainThreadFont: Sendable {
private let font: NSFont
init(_ font: NSFont) {
assert(Thread.isMainThread)
self.font = font
}
var value: NSFont {
assert(Thread.isMainThread)
return font
}
}
你可以像这样使用它:
var container = AttributeContainer()
container.appKit.foregroundColor = .red
container.appKit.font = MainThreadFont(.systemFont(ofSize: mySize)).value
这种方法确保 NSFont 只能从主线程访问,提供一定程度的安全性。然而,在 Apple 将 Sendable 一致性添加到 NSFont 之前,这只是一种解决方法。
一如既往,您应该彻底测试并发代码,以确保它在所有情况下都能正确运行。