LeadKit/docs/tifoundationutils/asyncoperation.md

128 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `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)
```