Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Nevyn Bengtsson: Promise, it's Async!

Realm
September 24, 2015
5.3k

Nevyn Bengtsson: Promise, it's Async!

Realm

September 24, 2015
Tweet

Transcript

  1. Nested scopes !.fetchFromNetwork(input) { intermediate in !.parseResponse(intermediate) { again in

    dispatch_async(dispatch_get_main_queue()) { updateUI(output) } } }
  2. Error handling !.fetchFromNetwork(input, callback: { intermediate in !.parseResponse(intermediate, callback: {

    again in dispatch_async(dispatch_get_main_queue()) { updateUI(output) } }, errback: { error in displayError("when parsing response, ", error) }) }, errback: { error in // This error is VERY far away from fetchFromNetwork! displayError("when fetching from network, ", error) })
  3. Cancellation var cancelled = false block var cancellable : Cancellable?

    let operation = !.fetchFromNetwork(input, callback: { intermediate in if(cancelled) return cancellable = !.parseResponse(intermediate, callback: { again in if(cancelled) return ... }) }) func cancel() { cancelled = true operation.cancel() cancellable?.stopOperation() }
  4. Help me Apple, you're my only hope! » A-value-in-the-future »

    Error handler » Cancellation » Dependencies ... IN FOUNDATION
  5. SPTask.swift 1/4 class TaskCompletionSource<T> { public let task: Task<T> func

    completeWithValue(value: T) func failWithError(error: NSError!) }
  6. SPTask.swift 2/4 class Task<T> { public func addCallback( on queue:

    dispatch_queue_t, callback: (T -> Void) ) -> Self public func addErrorCallback( on queue: dispatch_queue_t, callback: (NSError! -> Void) ) -> Self public func addFinallyCallback( on queue: dispatch_queue_t, callback: (Bool -> Void) ) -> Self }
  7. Callback example // Two of these three are executed immediately

    after each other network.fetch(resource).addCallback { json in let modelObject = parse(json) updateUI(modelObject) }.addErrback { error in displayDialog(error) }.addFinally { cancelled in if !cancelled { viewController.dismiss() } }
  8. SPTask.swift 3/4 class Task<T> { public func then<T2>(on queue:dispatch_queue_t, worker:

    (T -> T2)) -> Task<T2> public func then<T2>(chainer: (T -> Task<T2>)) -> Task<T2> }
  9. Chaining example // A: inline background parsing on _worker_queue func

    parse<T>(json) -> T network.fetch(resource) .then(on: _worker_queue) { json in // First this function runs, running parse on _worker_queue... return parse<MyModel>(json) }.addCallback { modelObject in // ... and when it's done, this function runs on main updateUI(modelObject) }.addErrorCallback { ... } // B: background parsing on Parser's own thread with async method class Parser { func parse<T>(json) -> Task<T> } network.fetch(resource) .then(_parser.parse) // parser is responsible for doing async work on its own .addCallback(updateUI) // and then updateUI is called with the model object .addErrorCallback(displayError)
  10. cancel and awaitAll example let imagesTask = Task.awaitAll(network.fetchImages(resource)).then { imageDatas

    in return Task.awaitAll(imageDatas.map { data in return parseImage(data) }) }.addCallback { images in showImages(image) } func viewDidDisappear() { // All downloading and parsing is cancelled imagesTask.cancel() }
  11. class NSURLConnection { func sendAsynchronousRequest( request: NSURLRequest, queue: NSOperationQueue, completionHandler:

    (NSURLResponse?, NSError?) -> Void ) } extension NSURLConnection { // : (NSURLRequest, queue) -> Task<NSURLResponse?> let asyncTaskRequest = Task.wrap(NSURLConnection.sendAsynchronousRequest) } NSURLConnection.asyncTaskRequest(myRequest, mainQueue) .then(_parser.parse) .then(_db.store) .then(_ui.update)
  12. extension Task { func wrap<P1, P2, R1> ( asyncFunction: (

    p1: P1, p2: P2, callback: ( r1: R1, err: NSError? ) -> Void ) -> Void ) -> (P1, P2) -> Task<R1> }
  13. extension Task { func wrap<P1, P2, R1> ( asyncFunction: (

    p1: P1, p2: P2, callback: ( r1: R1, err: NSError? ) -> Void ) -> Void ) -> (P1, P2) -> Task<R1> { let source = TaskCompletionSource<R1>() return { (p1: P1, p2: P2) -> Task<R1> in asyncFunc(p1: p1, p2: p2, callback: { (r1: R1, error: NSError?) -> Void in if let error = error { source.failWithError(error) } else { source.completeWithValue(r1) } }) return source.task } } }