Multithreading in iOS (2)

Bartosz Polaczyk

Agenda

  • Recap
  • Promise
  • RxSwift
  • Async/Await

Recap

Recap - async Operation

class AsyncOperation: Foundation.Operation {
    
    private var _executing = false
    private var _finished = false
    
    override internal(set) var isExecuting: Bool {
        get {
            return _executing
        }
        set {
            if _executing != newValue {
                willChangeValue(forKey: "isExecuting")
                _executing = newValue
                didChangeValue(forKey: "isExecuting")
            }
        }
    }
    
    override internal(set) var isFinished: Bool {
        get {
            return _finished
        }
        set {
            if _finished != newValue {
                willChangeValue(forKey: "isFinished")
                _finished = newValue
                didChangeValue(forKey: "isFinished")
            }
        }
    }
    


Recap - async Operation (2)

    override var isAsynchronous: Bool {
        return true
    }

    override func start() {
        if isCancelled {
            isFinished = true
            isExecuting = false
            return
        }
        isExecuting = true
        
        let session = URLSession.shared
        session.dataTask(with: URL(string: "https://httpbin.org/ip")!) { (data, response, error) in
            if self.isCancelled {
                self.isFinished = true
                self.isExecuting = false
                return
            }
            if let data = data {
                print(String(data: data, encoding: String.Encoding.utf8))
            }
            
            self.isExecuting = false
            self.isFinished = true
        }.resume()
    }
}
let queue = OperationQueue()
queue.addOperation(AsyncOperation())

Scenario

Promise

Promise

import PromiseKit

let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)

URLSession.shared.dataTask(with: urlRequest)
.then { json in
    print (json)
}

Promise

import PromiseKit

let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)

URLSession.shared.dataTask(with: urlRequest)
.then { json in
    let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)

    return URLSession.shared.dataTask(with: secondUrlRequest)
}.then { json in
    print (json)
}

Promise

import PromiseKit

let urlRequest = URLRequest(url: URL(string: "https://httpbin2.org/ip")!)

URLSession.shared.dataTask(with: urlRequest)
.then { json in
    let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin2.org/anything")!)

    return URLSession.shared.dataTask(with: secondUrlRequest)
}.then { json in
    print (json)
}.catch { error in
    print (error)
}

Promise

import PromiseKit

let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)

URLSession.shared.dataTask(with: urlRequest)
.then { json in
    let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)

    return URLSession.shared.dataTask(with: secondUrlRequest)
}.then { json in
    print (json)
}.always {
    
}.catch { error in
    print (error)
}

Existing World


makeNetworkRequest(url, completionHandler)

Expected Promise


dataTask(url) -> URLDataPromise

Creating a Promise


class URLSession{
    func dataTask(with request: URLRequest) -> URLDataPromise { 
	return Promise { fulfill, reject in

	// non-promise realm
			makeNetworkRequest(request, completionHandler:{ response in
				if (response.isOK){
					fullfill(response);
				}else{
					reject(response.error)
				}
			})
		}
	}
}

Scenario

RxSwift

RxSwift


import RxCocoa

let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)

URLSession.shared.rx.json(request: urlRequest)
    .subscribe { json in
        print(json)
    }

RxSwift


URLSession.shared.rx.json(request: urlRequest)
    .flatMap { json -> Observable<Any> in
        let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
        return URLSession.shared.rx.json(request: secondUrlRequest)
    }.subscribe { json in
        print(json)
    }

RxSwift


URLSession.shared.rx.json(request: urlRequest)
    .flatMap { json -> Observable<Any> in
        let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
        return URLSession.shared.rx.json(request: secondUrlRequest)
    }.subscribe(onNext: { json in
        print(json)
    }, onError:{ error in
        print (error)
    })

Promise


let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)

URLSession.shared.dataTask(with: urlRequest).then { json in
    let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
    return URLSession.shared.dataTask(with: secondUrlRequest)
}.then { json in
    print (json)
}.catch { error in
    print (error)
}

Other solution

Other solution


let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)
let firstResponse = URLSession.shared.dataTask(with: urlRequest)
...
let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
let secondResponse = secondURLSession.shared.dataTask(with: secondUrlRequest)
...
print (secondResponse)


Async/await

Async/await


let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)
await let firstResponse = URLSession.shared.dataTask(with: urlRequest)
let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
await let secondResponse = secondURLSession.shared.dataTask(with: secondUrlRequest)
print (secondResponse)

Async/await


async func makeTwoRequests() { 
	let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)
	await let firstResponse = URLSession.shared.dataTask(with: urlRequest)
	let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
	await let secondResponse = secondURLSession.shared.dataTask(with: secondUrlRequest)
	print (secondResponse)
}

Async/await error handling


async func makeTwoRequests() throws { 
	let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)
	await let firstResponse = try URLSession.shared.dataTask(with: urlRequest)
	let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
	await let secondResponse = try secondURLSession.shared.dataTask(with: secondUrlRequest)
	print (secondResponse)
}

Other solution


let urlRequest = URLRequest(url: URL(string: "https://httpbin.org/ip")!)
let firstResponse = URLSession.shared.dataTask(with: urlRequest)
...
let secondUrlRequest = URLRequest(url: URL(string: "https://httpbin.org/anything")!)
let secondResponse = secondURLSession.shared.dataTask(with: secondUrlRequest)
...
print (secondResponse)


Summary

  • Promises
  • Reactive Programming (RxSwift)
  • Async/await

Thank you!