【发布时间】:2022-12-11 13:09:44
【问题描述】:
语境
在使用 Swift 5.x 和 Xcode 14 构建的 Mac 应用程序中,我有一个控制器对象。这个对象有几个 @Published 属性,SwiftUI 视图可以观察到这些属性,所以我把这个对象放在 @MainActor 上,如下所示:
@MainActor
final class AppController: NSObject, ObservableObject
{
@Published private(set) var foo: String = ""
@Published private(set) var bar: Int = 0
private func doStuff() {
...
}
}
问题
此应用程序需要在 Mac 进入睡眠状态时采取某些操作,因此我在init() 方法中订阅了相应的通知,但由于 AppController 装饰有 @MainActor,我收到此警告:
override init()
{
NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.willSleepNotification, object: nil, queue: .main) { [weak self] note in
self?.doStuff() // "Call to main actor-isolated instance method 'doStuff()' in a synchronous nonisolated context; this is an error in Swift 6"
}
}
所以,我试图隔离它。但是(当然)编译器有一些新的抱怨。这次报错:
override init()
{
NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.willSleepNotification, object: nil, queue: .main) { [weak self] note in
Task { @MainActor in
self?.doStuff() // "Reference to captured var 'self' in concurrently-executing code
}
}
}
所以我这样做是为了解决这个问题:
override init()
{
NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.willSleepNotification, object: nil, queue: .main) { [weak self] note in
let JUSTSHUTUP: AppController? = self
Task { @MainActor in
JUSTSHUTUP?.doStuff()
}
}
}
问题
最后一位没有产生编译器错误并且似乎可以工作。但我不知道它是正确的还是最佳实践。
我确实理解为什么编译器会抱怨以及它试图保护我免受什么影响,但是尝试在现有项目中采用 Swift 并发是......痛苦的。
【问题讨论】:
标签: swift async-await appkit swift-concurrency