Versioning

To help with Cocoapods versioning syntax, all versions of Brisk compatible with Swift 2.2 will begin with Major/Minor 2.2. All versions comptible with Swift 2.3 will begin with Major/Minor 2.3. All versions compatible with Swift 3.0 will begin with Major/Minor 3.0, etc.

With Brisk the asynchronous functions can be coded using a seemingly-synchronous flow.
The asynchronous nature of the methods is hidden behind the custom operators. Unlike PromiseKit, all return values
remain in scope as well.

Calling Asynchronous Functions Synchronously

This section refers the idea of taking am asynchronous function and calling
it synchronously, generally for the purpose of chaining multiple asynchronous
operations. This is essentially the same offering of PromiseKit but without
the needless indentation and scope shuffle that comes with it.

To see a practical use case, refer to the Quick Look example above.

When we talk about an asynchronous function, it must abide by these characteristics:

Returns Void

Takes any number of input parameters

Has a single "completion" parameter that takes a function of the form (...) -> Void

Tip: Use <<+ for functions that
need to be called on the main thread (like UI updates). Use <<- for others.

In all of the above examples, execution of the outer thread is paused until the completion
handler $0 is called. Once $0 is called, the values passed into it are routed back
to the original assignment operation.

Note that the $0 handler can accommodate any number of parameters (e.g. getAlbum
above can take album and error), but it must be assigned to a variable that
of the same tuple. Also note that it is not possible to extract NSError parameters
to transform them into do/try/catch methodology — you will have to check the NSError
as part of the returned tuple.

Also note that the outer thread WILL WAIT until $0 is called. This means that
Brisk can only be used for functions that guarantee their completion handlers will
be called at some deterministic point in the future. It is not suitable for open-ended
asynchronous functions like NSNotification handlers.

Calling Synchronous Functions Asynchronously

There are many reasons to call synchronous functions asynchronously. It happens any
time you see this pattern:

dispatch_async(someQueue) {
completionHandler(..)
}

You’re burning three lines and an indentation scope just to route a single function call to
another queue.

An example of this is in the Quick Look example from the beginning of the documentation. This
routing must take place each time the completion handler is called on the main queue. It
has a negative impact on the readability of the overall function, since the actual function
name gets buried in the scope of the dispatch. Wouldn’t it be nice if that could be
accomplished in one line, with the function name first?

The ~>> and +>> operators introduced in Brisk can be thought of as the
synchronous->asynchronous translators. The main difference between the two is that
the +>> operator dispatches to the main queue, while the ~>> operator
allows you to specify the queue (or use the concurrent background queue by default).

For the examples below, consider the following normal synchronous functions:

In all of the above examples, the return values were ignored. This is generally fine
for the synchronous functions that return Void (like most completion handlers).
Because the functions are called asynchronously, you have to process the return
values asynchronously as well:

dispatch_async(someQueue) {
// syncReturnsParam(p: 3) is called on the main thread
// Its response is also handled on the main thread
syncReturnsParam +>> (p: 3) +>> { i in print(i) } // prints 4
// syncReturnsParam(p: 3) is called on the main thread
// Its response is handled on the global concurrent background queue
// Note the positions and difference between +>> and ~>>
syncReturnsParam +>> (p: 3) ~>> { i in print(i) } // prints 4
// syncReturnsParamTuple(p: 3) is called on the global concurrent background queue
// Its response is handled on an instantiated queue
syncReturnsParamTuple ~>> (p: 3) ~>> otherQueue ~>> { iInt, iStr in print(pInt) }
// Using the more functional style
syncReturnsParam~>>.on(otherQueue).async(p: 3) +>> { i in print(i) }
}

Optionals

When the function you are routing is an optional, you must use the ?~>> and ?+>>
operators when referencing the function:

Note that if you were using the syntax for optionalscompletionHandler?~>>.main.async(param)
— Swift 3.1 does not allow ? characters at the beginning of postfix
operators so you can no longer explicitly choose a queue name
like ".main". You can still use queues implicitly with the operator, likecompletionHandler?+>>.async(param)

Swift 3.x LibDispatch Additions

Brisk extensions DispatchQueue with functions that make the async function
more concise:

Another new function allows you to coalesce multiple async calls into a single execution,
based on an operationId. This is useful when several simultaneous asynchronous
actions want to trigger a block to occur (but you only want that block to occur once).

There are several variations of the above functions. See BriskDispatch.swift for more details.

Deprecated Swift 2.x GCD Additions

The following code examples show the GCD additions provided by Brisk for the Swift 2.x syntax. These are
fairly self-documenting. More information about each method can be found in its comment section. They are
included in the Swift 3.x release for backwards compatibility.

dispatch_main_async {
// Block runs on the main queue
}
dispatch_main_sync {
// Block runs on the main queue; this function does not return until
// the block completes.
}
dispatch_bg_async {
// Block runs on the global concurrent background queue
}
dispatch_async("myNewQueue") {
// Block runs on a brisk-created serial queue with the specified string ID.
// Calling this function multiple times with the same string will reuse the
// named queue. Useful for dynamic throw-away serial queues.
}
dispatch_main_after(2.0) {
dispatch_after(2.0, myQueue) {
// Block is called on specified queue after specified number of seconds using
// a loose leeway (+/- 0.1 seconds).
}
dispatch_main_after_exactly(2.0) {
dispatch_after_exactly(2.0, myQueue) {
// Block is called on specified queue after specified number of seconds using
// as tight a timer leeway as possible. Useful for animation timing but
// uses more battery power.
}
dispatch_main_every(2.0) { timer in
dispatch_every(2.0, myQueue) { timer in
dispatch_main_every_exact(2.0) { timer in
dispatch_every_exact(2.0, myQueue) { timer in
// Block is run on specified thread every N seconds.
// Stop the timer with:
dispatch_source_cancel(timer)
}
dispatch_main_once_after(2.0, "myOperationId") {
dispatch_once_after(2.0, myQueue, "myOperationId") {
// Block runs after specified time on specified queue. The block is
// only executed ONCE -- repeat calls to this function with the same
// operation ID will reset its internal timer instead of calling the
// block again. Useful for calling a completion block after several
// disparate asynchronous methods (e.g. saving the database to disk
// after downloading multiple records on separate threads.)
}
dispatch_each(myArray, myQueue) { element in
// Each element in the array has this block called with it as a parameter.
// Should be used on a concurrent queue.
}