我正在阅读此博客,因为我有类似的用例: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 用于防止数据争用。请参阅使用 Swift Actor 保护可变状态和使用 Swift Concurrency 消除数据争用。