https://github.com/hkellaway/asynctaskperformer
Performs lists of asynchronous tasks synchronously :arrow_right_hook:
https://github.com/hkellaway/asynctaskperformer
asynchronous-tasks ios swift
Last synced: about 1 year ago
JSON representation
Performs lists of asynchronous tasks synchronously :arrow_right_hook:
- Host: GitHub
- URL: https://github.com/hkellaway/asynctaskperformer
- Owner: hkellaway
- License: mit
- Created: 2018-07-06T13:34:46.000Z (almost 8 years ago)
- Default Branch: develop
- Last Pushed: 2018-11-24T20:27:55.000Z (over 7 years ago)
- Last Synced: 2025-01-03T03:45:30.783Z (over 1 year ago)
- Topics: asynchronous-tasks, ios, swift
- Language: Swift
- Homepage:
- Size: 70.3 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# AsyncTaskPerformer
Performs lists of asynchronous tasks synchronously :arrow_right_hook:
## Features
[](https://github.com/Carthage/Carthage)
## Getting Started
[Download AsyncTaskPerformer](https://github.com/hkellaway/AsyncTaskPerformer/archive/master.zip) and perform a `pod install` on the included `Demo` app to see AsyncTaskPerformer in action
### Swift Version
AsyncTaskPerformer is currently compatible with Swift 4.2.
### Installation with CocoaPods
```ruby
pod 'AsyncTaskPerformer', :git => 'https://github.com/hkellaway/AsyncTaskPerformer.git', :tag => '0.1.0'
```
### Installation with Carthage
```
github "hkellaway/AsyncTaskPerformer"
```
## Usage
AsyncTaskPerformer takes lists of asynchronous tasks and processes them in order. It can do so for multiple uses cases:
* The list of asynchronous tasks should be processed in order with a single completion point - but without concern for if errors occur in any nor require a typed result (Use [SynchronousDispatchGroup](#SynchronousDispatchGroup))
* The list of asynchronous tasks should be processed in order, report their result using the same type, and have a single completion point - the completion point must report the result of attempting each task in order, either with an error or the final typed result (Use [SynchronousOperationQueue](#SynchronousOperationQueue))
## SynchronousDispatchGroup
`SynchronousDispatchGroup` uses a `DispatchGroup` to synchronize its list of asynchrnous tasks. It is better used for tasks that don't need to be typed and don't need to halt execution if an error occurs. Let's look at an example of usage.
First, create tasks that conform to `AsyncTask`. Let's imagine a task that prints out "Hello World" - we'll give our tasks an `id` so we can confirm they're processing in order.
``` swift
struct SayHelloTask: AsyncTask {
let id: Int
func execute(completion: @escaping () -> Void) {
print("Hello World \(id)")
completion()
}
}
```
The critical aspect of an `AsyncTask` is that it independently knows how ot `execute` a piece of work.
Next, create a `SynchronousDispatchGroup` and give it a list of `AsyncTasks`s to perform, as well as a single completion point.
``` swift
let tasks: [AsyncTask] = [SayHelloTask(id: 1), SayHelloTask(id: 2), SayHelloTask(id: 3) ]
let synchronousDispatchGroup = SynchronousDispatchGroup()
synchronousDispatchGroup.executeTasks(tasks) {
print("Goodbye")
}
```
The output from this will be:
```
Hello World 1
Hello World 2
Hello World 3
Goodbye
```
### SynchronousOperationQueue
`SynchronousOperationQueue` uses an `OperationQueue` to synchronize its list of asynchrnous tasks. It is better used for tasks that have a specific type which the tasks perform work on in-order. For example, in an e-commerce application we might need to remove Items from the Bag one-by-one and report the state of the Bag after each successful removal.
If an error is encountered in the midst of processing the tasks, the rest of the tasks are cancelled and the completion is called early.
Let's imagine we have an `api` that, when given an `itemID` will `removeFromBag` the provided `Item` and report back the resulting state of the `Bag` (or, an error if the Item was not present in the Bag).
First, create an operation that inherits from `AsyncOperationWithCompletion`.
``` swift
final class RemoveItemFromBagOperation: AsyncOperationWithCompletion {
let itemID: Int
let api: ECommAPI
init(id: Int, api: FakeAPI) {
self.id = id
self.api = api
}
override func main() {
api.removeFromBag(item: itemID) { [weak self] (updatedBag, error) in
self?.completion?(updatedBag, error)
self?.finish()
}
}
}
```
The critical aspect of `AsyncOperationWithCompletion` is that it calls its own `completion` closure then calls `finish()`.
Next, create a `SynchronousOperationQueue` and give it a list of tasks to perhaps - as well as a starting value and a single completion point.
``` swift
let currentBag = Bag(items: [Item(id: 1), Item(id: 2), Item(id: 3), Item(id: 4)])
let itemsToRemove = [2, 4]
let operations = itemsToRemove.map { RemoveItemFromBagOperation(itemID: $0, api: api) }
let synchronousOperationQueue = SynchronousOperationQueue(defaultValue: currentBag)
synchronousOperationQueue.executeOperations(operations) { (finalBag, error) in
if let error = error {
print(":()
} else {
print("Updated Bag: " + finalBag)
}
}
```
The result from this, if all API calls completed successfully, would be the Bag updated such that Item 2 and Item 4 have been removed.
## Credits
AsyncTaskPerformer was created by [Harlan Kellaway](http://harlankellaway.com).
## License
AsyncTaskPerformer is available under the MIT license. See the [LICENSE](https://raw.githubusercontent.com/hkellaway/AsyncTaskPerformer/master/LICENSE) file for more info.