128 lines
4.4 KiB
Markdown
128 lines
4.4 KiB
Markdown
|
||
# `AsyncOperation<Result, Error>` - generic сабкласс Operation
|
||
|
||
Позволяет запускать:
|
||
|
||
- асинхронный код внутри операции
|
||
- собирать цепочки из операций
|
||
- подписываться на результат выполнения
|
||
|
||
## Базовые операции
|
||
|
||
"Из коробки", на данный момент, доступен всего один сабкласс асинхронной операции, потому что больше обычно и не нужно.
|
||
Но можно наследоваться и создавать собственные сабклассы при необходимости.
|
||
|
||
### `ClosureAsyncOperation<Result, Error>`
|
||
|
||
Операция принимающая некий closure, который по окончании своей работы вызовет completion, переданный ему параметром
|
||
|
||
```swift
|
||
import Foundation
|
||
import TIFoundationUtils
|
||
|
||
let intResultOperation = ClosureAsyncOperation<Int, Never> { completion in
|
||
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(3)) {
|
||
completion(.success(1))
|
||
}
|
||
return Cancellables.nonCancellable()
|
||
}
|
||
```
|
||
|
||
## Базовые операторы
|
||
|
||
На данный момент реализовано четыре оператора:
|
||
|
||
- `map(mapOutput:mapFailure:)` - конвертирует ResultType в новый NewResultType и ErrorType в новый NewErrorType
|
||
- `observe(onSuccess:onFailure)` - просто вызывает переданные callback'и при получении результата или ошибки
|
||
- `flatMap<NewOutput>(_:)` - подписывается на результат выполнения нового AsyncOperation полученного из closure
|
||
- `flatMapError<NewFailure>(_:)` - подписывается на результат выполнения нового AsyncOperation полученного из closure
|
||
|
||
### Пример запуска асинхронных операци с применением операторов в последовательной очереди и вывод результатов
|
||
|
||
```swift
|
||
let operationQueue = OperationQueue()
|
||
operationQueue.maxConcurrentOperationCount = 1
|
||
|
||
ClosureAsyncOperation<Int, Never> { completion in
|
||
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(3)) {
|
||
completion(.success(1))
|
||
}
|
||
return Cancellables.nonCancellable()
|
||
}
|
||
.map { $0 * 2 }
|
||
.observe(onSuccess: { result in
|
||
debugPrint("Async operation one has finished with \(result)")
|
||
})
|
||
.add(to: operationQueue)
|
||
|
||
ClosureAsyncOperation<String, Never> { completion in
|
||
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(1)) {
|
||
completion(.success("Success"))
|
||
}
|
||
return Cancellables.nonCancellable()
|
||
}
|
||
.observe(onSuccess: { result in
|
||
debugPrint("Async operation two has finished with \(result)")
|
||
})
|
||
.add(to: operationQueue)
|
||
```
|
||
|
||
В консоли будет выведено:
|
||
|
||
```
|
||
"Async operation one has finished with 2"
|
||
"Async operation two has finished with Success"
|
||
```
|
||
|
||
### Пример использования оператора flatMap у AsyncOperaton
|
||
|
||
```swift
|
||
import TISwiftUtils
|
||
|
||
extension StorageKey {
|
||
static var loyaltyCardNumber: StorageKey<String> {
|
||
.init(rawValue: "loyaltyCardNumber")
|
||
}
|
||
}
|
||
|
||
struct CardService {
|
||
enum Failure: Error {
|
||
case noCardFound
|
||
case cardFetchError
|
||
}
|
||
|
||
private let operationQueue = OperationQueue()
|
||
|
||
private let asyncStorage = StringValueDefaultsStorage(defaults: .standard, storageKey: .loyaltyCardNumber)
|
||
.async(on: .global())
|
||
|
||
func requestCardTitle(cardNumber: String) -> AsyncOperation<String, Failure> {
|
||
.just(success: "Supreme card")
|
||
// .just(failure: .cardFetchError)
|
||
}
|
||
|
||
func getSavedCardTitle(completion: @escaping UIParameterClosure<Result<String, Failure>>) -> Cancellable {
|
||
ClosureAsyncOperation { completion in
|
||
asyncStorage.getValue {
|
||
completion($0.mapError { _ in
|
||
.noCardFound
|
||
})
|
||
}
|
||
}
|
||
.flatMap {
|
||
requestCardTitle(cardNumber: $0)
|
||
}
|
||
.observe(onResult: completion)
|
||
.add(to: operationQueue)
|
||
}
|
||
}
|
||
|
||
let cardService = CardService()
|
||
|
||
cardService.getSavedCardTitle { result in
|
||
debugPrint(result)
|
||
}
|
||
|
||
Nef.Playground.needsIndefiniteExecution(true)
|
||
```
|