Yakka

Features

Yakka is a toolkit for coordinating the doing of stuff. Here's what it does:

Makes it trivial to do arbitrary work of an asynchronous nature in the background and know when it finishes.

Lets you easily group and/or chain independent chunks of background work to form trackable processes.

Allows any number of interested parties to listen/track the progress and outcome of background work.

Gives fine control over the GCD execution queues involved if required.

Yakka can be used for throwaway code you just need run asynchronously in the background, or it can be leveraged to coordinate reusable components in a complex system. There are many different ways of tackling this kind of thing – hopefully this one works for you!

The basics

There's 3 main things involved in Yakka:

Task objects - these encapsulate work that needs doing.

Line objects - these control the starting of tasks.

Process objects - a task's in-work companion, used to report progress and finish.

You can create a task in place using a closure, or you can create a subclass and provide the work closure in there. Depends whether you want the work to be reusable in other places.

Lines can be created in place as well if you simply want to make a task start. Alternatively they can be held onto and used to control the number of things happening at once (this is their main purpose).

If you want to group otherwise independent tasks into a dependent group so that you can wait on their combined completion, you can do so using SerialTask or ParallelTask. These are also just Task subclasses, so you can create them easily, add an onFinish handler, and send them down a line.

GCD is used internally in the following ways:

Task work execution happens on a workQueue (accessible via Process object if/when task needs a queue along the way). This is assigned by the Line when it starts the task.

Lines define the workQueue as a global concurrent background queue unless you give it a specific one upon initialization.

Feedback handlers will execute on main unless you provide an alternative queue. Objects which provide feedback can be given a default queue to use (ie override main in all cases), and/or can be given a queue to use for a specific feedback handler.

These examples all complete their work by the end of the work closure (they're synchronous), but you can check out the tests file for a few more examples where work completes at arbitrary later times.

Lifecycle of a Yakka Task:

Not Started

Running

Cancelling

Successful | Cancelled | Failed

Some points about that:

Flows downward and never back up.

Cancelling only leads to Cancelled if task is cancel-aware and bails out.

If a task never moves into Running, no handlers will ever be called.

Tasks retain themselves only while Running and Cancelling.

Because it never flows backwards, tasks cannot be restarted, even if cancelled.

Other details:

Tasks retain themselves after starting, until the finish closure is called.

The Process object given to a Task's work closure is safe to interact with from any thread.

Provide progress either by push or pull (polling) or not at all, depending on your work.

Detect and support cancellation requests either by push or pull or not at all, depending on your work.

Task instances are single shot – they can't be run again after they finish.

A note on memory management:

Tasks retain themselves while running, which is done deliberately to make them easier to work with. The working queue used by the task is also retained while running. All you gotta do is make sure your work eventually finishes by calling one of the methods on the process object, and that the process object isn't strongly retained beyond that point.

SerialTask and ParallelTask both retain the tasks you give to them regardless of whether or not they are started. They retain themselves while running because they're also just Tasks.

Lines do not retain themselves and in throwaway situations they will be deallocated as they fall out of scope, but they are not needed for tasks to continue running.

Event closures onStart and onFinish are fine to retain the task within them, as they will be let go of after those events occur. However onProgress and onRetry closures are retained during the lifetime of the task, so you do not want to strongly capture the task within those event closures.

Yakka?

As in Hard Yakka – classic Aussie slang for work. It's derived from 'yaga', which is a term from the Yagara language spoken by indigenous peoples of the region now known as Brisbane.

Requirements & Platforms

Swift 4.0

iOS

macOS

watchOS

tvOS

Linux

Installation

Cocoapods

Yakka is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod "Yakka"

Carthage

Yakka can be installed using Carthage. Add the following to your Cartfile:

github "KieranHarper/Yakka" ~> 2.0

Swift Package Manager

Installation through the Swift Package Manager is also supported. Add the following to your Package file: