Slide 1

Slide 1 text

Swift Sync and Async Error Handling iOS Conf Singapore - October 2015 — @Javi 1 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 2

Slide 2 text

Agenda → Traditional Asynchronous Code → Problems with Traditional Error Handling → Result vs throws → Modeling asynchronous computation: Future → Making Result and throws play together 2 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 3

Slide 3 text

Traditional asynchronous code 3 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 4

Slide 4 text

Traditional asynchronous code struct User { let avatarURL: NSURL } func requestUserInfo(userID: String, completion: (User?, NSError?) -> ()) func downloadImage(URL: NSURL, completion: (UIImage?, NSError?) -> ()) func loadAvatar(userID: String, completion: (UIImage?, NSError?) -> ()) { requestUserInfo(userID) { user, error in if let user = user { downloadImage(user.avatarURL) { avatar, error in if let avatar = avatar { completion(avatar, nil) } else { completion(nil, error!) } } } else { completion(nil, error!) } } } 4 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 5

Slide 5 text

Traditional asynchronous code 5 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 6

Slide 6 text

Traditional asynchronous code func downloadImage(URL: NSURL, completion: (UIImage?, NSError?) -> ()) (.Some, .None) (.None, .Some) (.Some, .Some) (.None, .None) 6 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 7

Slide 7 text

(.Some, .Some) (.None, .None) 7 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 8

Slide 8 text

Error Handling func downloadImage(URL: NSURL, completion: (UIImage?, NSError?) -> ()) downloadImage(url) { imageOrNil, errorOrNil in if error = errorOrNil { // What if image is also not nil?? } else if image = imageOrNil { } } 8 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 9

Slide 9 text

Error Handling var error: NSError? let string = NSString(contentsOfFile:path encoding:NSUTF8Encoding error:&error) if string == nil { // Oops: if error.code == NSFileReadNoSuchFileError { // ... } else if ... } 9 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 10

Slide 10 text

10 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 11

Slide 11 text

11 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 12

Slide 12 text

12 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 13

Slide 13 text

13 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 14

Slide 14 text

NSError Alternative protocol ErrorType { } enum UserInfoErrorDomain: ErrorType { case UserDoesNotExist case UserRequestFailure(reason: String) case NetworkRequestFailure(underlyingError: NSError) } extension NSError: ErrorType { } 14 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 15

Slide 15 text

NSError Alternative enum NoError: ErrorType { } let error = NoError(?) 15 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 16

Slide 16 text

Result enum Result { case Success(T) case Failure(E) } Result by Rob Rix: https://github.com/antitypical/Result 16 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 17

Slide 17 text

Swift's throws 17 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 18

Slide 18 text

Swift's throws func readFile(path: String) throws -> NSData 18 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 19

Slide 19 text

Swift's throws func readFile(path: String) throws -> NSData // throws... what exactly? 19 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 20

Slide 20 text

Swift's throws func readFile(path: String) throws -> NSData Functionally equivalent to func readFile(path: String) -> Result 20 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 21

Slide 21 text

Swift's throws func readFile(path: String) throws -> NSData do { let contents = try readFile("path/to/my/file") } catch(SomeTypeOfError) { // How can I know which errors I should match..? } catch { // catch-all block. } 21 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 22

Slide 22 text

Swift's throws func readFile(path: String) throws -> NSData let contents: NSData? = try? readFile("path/to/my/file") 22 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 23

Slide 23 text

Swift's throws func readFile(path: String) -> Result let file = readFile("path/to/my/file") switch file { case let .Succcess(value): // ... case let .Failure(error): // This `error` variable has type information! } 23 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 24

Slide 24 text

Swift's throws Hopefully in a future version of Swift ... func readFile(path: String) throws FileIOError -> NSData 24 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 25

Slide 25 text

Error handling in Asynchronous APIs 25 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 26

Slide 26 text

Future 26 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 27

Slide 27 text

Futures → Encapsulate a deferred computation. → Treat values that incur a delay to be retrieved as if they were regular values. → Allow us to treat errors as first class citizens. → Easily composable. 27 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 28

Slide 28 text

Future struct Future { typealias ResultType = Result typealias Completion = ResultType -> () typealias AsyncOperation = Completion -> () private let operation: AsyncOperation } 28 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 29

Slide 29 text

Future struct Future { init(operation: AsyncOperation) { self.operation = operation } func start(completion: Completion) { self.operation() { result in completion(result) } } } 29 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 30

Slide 30 text

Future.map(): transforming the computed value 30 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 31

Slide 31 text

Future.map(): transforming the computed value struct User { let avatarURL: NSURL } func requestUserInfo(userID: String) -> Future func requestUserAvatarURL(userID: String) -> Future { return requestUserInfo(userID) .map { $0.avatarURL } } 31 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 32

Slide 32 text

Future.map(): transforming the computed value struct Future { func map(f: T -> U) -> Future } 32 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 33

Slide 33 text

map() in other types struct Array { func map(f: T -> U) -> [U] } enum Optional { func map(f: T -> U) -> U? } struct Future { func map(f: T -> U) -> Future } 33 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 34

Slide 34 text

Future.map(): transforming the computed value func map(f: T -> U) -> Future { // Return a new Future w/ a new operation... return Future(operation: { completion in }) } 34 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 35

Slide 35 text

Future.map(): transforming the computed value func map(f: T -> U) -> Future { return Future(operation: { completion in // Retrieve the value from self... self.start { result in } }) } 35 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 36

Slide 36 text

Future.map(): transforming the computed value func map(f: T -> U) -> Future { return Future(operation: { completion in self.start { result in // Consider .Success and .Failure... switch result { } } }) } 36 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 37

Slide 37 text

Future.map(): transforming the computed value case let .Success(value): // Call completion with the transformed value completion(Result.Success(f(value))) 37 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 38

Slide 38 text

Future.map(): transforming the computed value case let .Failure(error): // We didn't get a value: no transformation completion(Result.Failure(error)) 38 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 39

Slide 39 text

Future.map(): transforming the computed value func map(f: T -> U) -> Future { return Future(operation: { completion in self.start { result in switch result { case let .Success(value): completion(Result.Success(f(value))) case let .Failure(error): completion(Result.Failure(error)) } } }) } 39 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 40

Slide 40 text

Future.andThen(): concatenating async work 40 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 41

Slide 41 text

Future.andThen(): concatenating async work func requestUserAvatarURL(userID: String) -> Future func downloadImage(URL: NSURL) -> Future func downloadUserAvatar(userID: String) -> Future { return requestUserAvatarURL(userID) .andThen(downloadImage) } 41 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 42

Slide 42 text

Future.andThen(): concatenating async work struct Future { func andThen(f: T -> Future) -> Future } 42 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 43

Slide 43 text

Future.andThen(): concatenating async work func andThen(f: T -> Future) -> Future { return Future(operation: { completion in } } 43 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 44

Slide 44 text

Future.andThen(): concatenating async work func andThen(f: T -> Future) -> Future { return Future(operation: { completion in self.start { firstFutureResult in } }) } 44 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 45

Slide 45 text

Future.andThen(): concatenating async work func andThen(f: T -> Future) -> Future { return Future(operation: { completion in self.start { firstFutureResult in switch firstFutureResult { case let .Success(value): // ... case let .Failure(error): // ... } } }) } 45 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 46

Slide 46 text

Future.andThen(): concatenating async work case let .Success(value): let nextFuture = f(value) 46 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 47

Slide 47 text

Future.andThen(): concatenating async work case let .Success(value): let nextFuture = f(value) nextFuture.start { finalResult in completion(finalResult) } 47 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 48

Slide 48 text

Future.andThen(): concatenating async work case let .Failure(error): completion(Result.Failure(error)) 48 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 49

Slide 49 text

Future.andThen(): concatenating async work func andThen(f: T -> Future) -> Future { return Future(operation: { completion in self.start { firstFutureResult in switch firstFutureResult { case let .Success(value): f(value).start(completion) case let .Failure(error): completion(Result.Failure(error)) } } }) } 49 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 50

Slide 50 text

We can go from this... func loadAvatar(userID: String, completion: (UIImage?, NSError?) -> ()) { requestUserInfo(userID) { user, error in if let user = user { downloadImage(user.avatarURL) { avatar, error in if let avatar = avatar { completion(avatar, nil) } else { completion(nil, error) } } } else { completion(nil, error) } } } 50 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 51

Slide 51 text

... To this func requestUserInfo(userID: String) -> Future func downloadImage(URL: NSURL) -> Future func loadAvatar(userID: String) -> Future { return requestUserInfo(userID) .map { $0.avatarURL } .andThen(downloadImage) } 51 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 52

Slide 52 text

Mixing it all up Result and throws 52 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 53

Slide 53 text

Result and throws throws => Result extension Result { public init(@autoclosure _ f: () throws -> T) { do { self = .Success(try f()) } catch { self = .Failure(error as! Error) } } } 53 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 54

Slide 54 text

Result and throws Result => throws extension Result { public func dematerialize() throws -> T { switch self { case .Success(value): return value case let .Failure(error): throw error } } } 54 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 55

Slide 55 text

Result and throws Future => throws let avatarFuture = loadAvatar("4815162342") avatarFuture.start { result in do { let avatar = try result.materialize() } catch { // handle `error` } } 55 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 56

Slide 56 text

Limitations of Futures → Only represent computation to retrieve one value. → Can't encapsulate streams of values. → Only consumer (pull) driven, not producer (push) driven. 56 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 57

Slide 57 text

ReactiveCocoa Signals > Futures 57 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 58

Slide 58 text

Follow-up Resources → ReactiveCocoa: https://github.com/ ReactiveCocoa/ReactiveCocoa → Railway Oriented Programming: http:// fsharpforfunandprofit.com/posts/recipe-part2/ 58 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015

Slide 59

Slide 59 text

Thanks! Questions? 59 — "Swift Sync and Async Error Handling" - Javier Soto. iOS Conf Singapore - October 2015