我正在阅读这个博客,因为我有一个类似的用例:https://kelvas09.github.io/blog/posts/closure-delegate-to-async/
我注意到以下片段:
actor BluetoothLEScanWrapper {
enum BluetoothLEScanError: Error {
case bluetoothNotAvailable
}
private let bluetoothLEDelegate: BluetoothLEDelegate = BluetoothLEDelegate()
private var activeTask: Task<[BluetoothLEDevice], Error>?
func scan(for seconds: Double = 3.0) async throws -> [BluetoothLEDevice] {
if let existingTask = activeTask {
return try await existingTask.value
}
let task = Task<[BluetoothLEDevice], Error> {
guard bluetoothLEDelegate.bluetoothIsOn else {
activeTask = nil
throw BluetoothLEScanError.bluetoothNotAvailable
}
self.bluetoothLEDelegate.central.scanForPeripherals(withServices: nil)
try await Task.sleep(nanoseconds: (UInt64(seconds) * 1_000_000_000))
let devices = bluetoothLEDelegate.foundPeripheral.compactMap { BluetoothLEDevice(peripheral: $0) }
bluetoothLEDelegate.central.stopScan()
bluetoothLEDelegate.foundPeripheral = []
activeTask = nil
return devices
}
activeTask = task
return try await task.value
}
...
作者特别呼吁注意演员的使用。据我了解,这是为了避免重复调用activeTask
时的数据竞争scan()
。我的理解正确吗?谢谢您的帮助。
是的,你是对的。Actor 用于防止数据争用。请参阅 WWDC 视频使用 Swift Actor 保护可变状态和使用 Swift Concurrency 消除数据竞争。或者参见Swift 编程语言:并发:Actors。
该
scan
方法将与参与者隔离,Task
它创建的方法也将与参与者隔离。