Bry*_*yan 6 appkit async-await swift swift-concurrency
在使用 Swift 5.x 和 Xcode 14 构建的 Mac 应用程序中,我有一个控制器对象。该对象具有@PublishedSwiftUI 视图观察到的多个属性,因此我将该对象放置在@MainActor这样的位置:
@MainActor
final class AppController: NSObject, ObservableObject
{
@Published private(set) var foo: String = ""
@Published private(set) var bar: Int = 0
private func doStuff() {
...
}
}
Run Code Online (Sandbox Code Playgroud)
当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"
}
}
Run Code Online (Sandbox Code Playgroud)
所以,我试图隔离它。但是(当然)编译器有一些新的问题需要抱怨。这次报错了:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以我这样做是为了解决这个问题:
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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后一位不会产生编译器错误并且似乎可以工作。但我不知道这是否正确或最佳实践。
我确实理解编译器为什么会抱怨以及它试图保护我免受什么影响,但尝试在现有项目中采用 Swift Concurrency 是......痛苦的。
您可以使用您的Task { @MainActor in ... }模式,但将[weak self]捕获列表添加到Task:
NSWorkspace.shared.notificationCenter.addObserver(\n forName: NSWorkspace.willSleepNotification,\n object: nil,\n queue: .main\n) { [weak self] note in\n Task { @MainActor [weak self] in\n self?.doStuff()\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nFWIW,在 Swift 并发中,我们可能会放弃旧的基于完成处理程序的观察者,而不是观察者模式,而是使用异步序列,notifications(named:object:):
@MainActor\nfinal class AppController: ObservableObject {\n private var notificationTask: Task<Void, Never>?\n\n deinit {\n notificationTask?.cancel()\n }\n\n init() {\n notificationTask = Task { [weak self] in\n let sequence = NSWorkspace.shared.notificationCenter.notifications(named: NSWorkspace.willSleepNotification)\n\n for await notification in sequence {\n self?.doStuff(with: notification)\n }\n }\n }\n\n private func doStuff(with notification: Notification) { \xe2\x80\xa6 }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
1654 次 |
| 最近记录: |