Person is an example of a struct that contains information about the person.
MyService is an example of a class that serves as an entry point to the model. Works in a background.
MyViewController is an example of a class that manages UI-related instances. Works on the main queue.
Code on callbacks
extension MyViewController {
func present(personWithID identifier: String) {
myService.fetch(personWithID: identifier) {
(person, error) in
/* do not forget to dispatch to the main queue */
DispatchQueue.main.async {
/* do not forget the [weak self] */
[weak self] in
guard let strongSelf = self
else { return }
if let person = person {
strongSelf.present(person: person)
} else if let error = error {
strongSelf.present(error: error)
} else {
fatalError("There is neither person nor error. What has happened to this world?")
}
}
}
}
}
extension MyService {
func fetch(personWithID: String, callback: @escaping (Person?, Error?) -> Void) {
/* ... */
}
}
“do not forget” comment x2
the block will be retained and called even if MyViewController was already deallocated
Code with other libraries that provide futures
extension MyViewController {
func present(personWithID identifier: String) {
myService.fetch(personWithID: identifier)
/* do not forget to dispatch to the main queue */
.onComplete(executor: .main) {
/* do not forget the [weak self] */
[weak self] (completion) in
if let strongSelf = self {
completion.onSuccess(strongSelf.present(person:))
completion.onFailure(strongSelf.present(error:))
}
}
}
}
extension MyService {
func fetch(personWithID: String) -> Future<Person> {
/* ... */
}
}
“do not forget” comment x2
the block will be retained and called even if MyViewController was already deallocated
let futurePrimeNumbers: Future<[Int]> = future { primeNumbers(to: 10_000_000) }
Applying transformation
let futureSquaredPrimeNumbers = futurePrimeNumbers
.map { (primeNumbers) -> [Int] in
return primeNumbers.map { (number) -> Int
return number * number
}
}
Synchronously waiting for completion
if let fallibleNumbers = futurePrimeNumbers.wait(seconds: 1.0) {
print("Number of prime numbers is \(fallibleNumbers.success?.count)")
} else {
print("Did not calculate prime numbers yet")
}
Subscribing for completion
futurePrimeNumbers.onComplete { (falliblePrimeNumbers) in
print("Number of prime numbers is \(falliblePrimeNumbers.success?.count)")
}
Combining futures
let futureA: Future<A> = /* ... */
let futureB: Future<B> = /* ... */
let futureC: Future<C> = /* ... */
let futureABC: Future<(A, B, C)> = zip(futureA, futureB, futureC)
Transition from callbacks-based flow to futures-based flow:
let channelOfSquaredPrimeNumbers = channelOfPrimeNumbers
.map { (number) -> Int in
return number * number
}
Synchronously iterating over update values.
for number in channelOfPrimeNumbers {
print(number)
}
Synchronously waiting for completion
if let fallibleNumberOfPrimes = channelOfPrimeNumbers.wait(seconds: 1.0) {
print("Number of prime numbers is \(fallibleNumberOfPrimes.success)")
} else {
print("Did not calculate prime numbers yet")
}
Synchronously waiting for completion #2
let (primeNumbers, numberOfPrimeNumbers) = channelOfPrimeNumbers.waitForAll()
func makeChannelOfPrimeNumbers(to n: Int) -> Channel<Int, Int> {
return channel { (update) -> Int in
var numberOfPrimeNumbers = 0
var isPrime = Array(repeating: true, count: n)
for number in 2..<n where isPrime[number] {
numberOfPrimeNumbers += 1
update(number)
// updating seive
var seiveNumber = number + number
while seiveNumber < n {
isPrime[seiveNumber] = false
seiveNumber += number
}
}
return numberOfPrimeNumbers
}
}
A complete set of primitives for concurrency and reactive programming on Swift
powerful primitives
Future
,Promise
,Channel
,Producer
,Sink
,Cache
, …versatile transformations
map
,filter
,recover
,debounce
,distinct
, …convenient combination
flatMap
,merge
,zip
,sample
,scan
,reduce
, …improves existing things
less boilerplate code
extendable
URLSession
, UI controls,CoreData
, …all platforms
documentation
simple integration
Communication
Reactive Programming
reactive properties
bindings
.observeOn(MainScheduler.instance)
and.disposed(by: disposeBag)
contexts usage
[weak self]
DispatchQueue.main.async { ... }
.observeOn(MainScheduler.instance)
In Depth
Let’s assume that we have:
Person
is an example of a struct that contains information about the person.MyService
is an example of a class that serves as an entry point to the model. Works in a background.MyViewController
is an example of a class that manages UI-related instances. Works on the main queue.Code on callbacks
Code with other libraries that provide futures
Code with AsyncNinja
Using Futures
Let’s assume that we have function that finds all prime numbers lesser than n
Making future
Applying transformation
Synchronously waiting for completion
Subscribing for completion
Combining futures
Transition from callbacks-based flow to futures-based flow:
Transition from futures-based flow to callbacks-based flow
Using Channels
Let’s assume we have function that returns channel of prime numbers: sends prime numbers as finds them and sends number of found numbers as completion
Applying transformation
Synchronously iterating over update values.
Synchronously waiting for completion
Synchronously waiting for completion #2
Subscribing for update
Subscribing for completion
Making
Channel