Eu estava lendo este blog, pois tenho um caso de uso semelhante: https://kelvas09.github.io/blog/posts/closure-delegate-to-async/
Notei o seguinte trecho:
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
}
...
O autor chama especificamente a atenção para o uso do ator. Pelo que entendi, isso é para evitar corridas de dados activeTask
caso scan()
seja chamado repetidamente. Meu entendimento está correto? Obrigado pela ajuda.
Sim você está correto. Atores são usados para evitar corridas de dados. Veja os vídeos da WWDC Proteja o estado mutável com atores Swift e elimine corridas de dados usando Swift Concurrency . Ou consulte A linguagem de programação Swift: Simultaneidade: Atores .
O
scan
método ficará isolado do ator, assim como oTask
que ele cria.