Extending Foundation
Swift Meetup Hamburg • 2016–09–21 • @herzi
Recap: Promises
createMagicPromise().then { reply in
if reply.response.statusCode != 200 {
throw RESTError.badResponse(reply.response)
}
// 🤔 : Still need to validate the content type.
return JSON.parse(data: reply.data)
}.then { json in
return User(serialized: json)
}.then { user in
// Do something with the user object.
}.fail { error in
// Don’t handle errors like this when being outside of keynote.
fatalError("FIXME: Handle error: (error)")
}.done()
URLSession + Promises
typealias Reply = (response: URLResponse,
data: Data)
// I really don’t have a better name.
protocol RESTful {
func get(url: URL) -> Promise<Reply>
}
URLSession
+Promise.swift
URLSession+Promise
extension URLSession: RESTful {
func get(url: URL) -> Promise<Reply> {
/* TODO: Use
* URLSession.dataTask(with:, completionHandler:)
*/
fatalError("Unimplemented.")
}
}
// Looks good, no?
URLSession+Promise
extension URLSession: RESTful {
func get(url: URL) -> Promise<Reply> {
/* TODO: Use
* URLSession.dataTask(with:, completionHandler:)
*/
fatalError("Unimplemented.")
}
}
// Looks good, no? No.
How to Test?
extension URLSession: RESTful {
func get(url: URL) -> Promise<Reply> {
/* TODO: Use
* URLSession.dataTask(with:, completionHandler:)
*/
fatalError("Unimplemented.")
}
}
// Looks good, no? No, I don’t want to set up an HTTP server.
Let’s try again
protocol URLSessionLike {
typealias Completion = (Data?, URLResponse?, Error?) -> Void
func dataTask(with url: URL,
completionHandler: @escaping Completion)
-> URLSessionDataTask
}
extension URLSession: URLSessionLike {}
Let’s try again (cont.)
protocol URLSessionLike: RESTful {
typealias Completion = (Data?, URLResponse?,
Error?) -> Void
func dataTask(with url: URL,
completionHandler: @escaping Completion)
-> URLSessionDataTask
}
extension URLSession: URLSessionLike {}



extension URLSessionLike {
func get(url: URL) -> Promise<Reply> {
fatalError("Still unimplemented.")
}
}
Testing the Protocol
class MockSession: URLSessionLike {
internal func dataTask(with url: URL,
completionHandler: @escaping
URLSessionLike.Completion)
-> URLSessionDataTask
{
DispatchQueue.main.async {
let error = URLError(.notConnectedToInternet)
completionHandler(nil, nil, error)
}
}
}
/* Later you will only mock RESTful things and return
* Promises directly. */
Questions?
Slides will be uploaded and linked in the Meetup Group

Swift Meetup HH 2016/09

  • 1.
    Extending Foundation Swift MeetupHamburg • 2016–09–21 • @herzi
  • 2.
    Recap: Promises createMagicPromise().then {reply in if reply.response.statusCode != 200 { throw RESTError.badResponse(reply.response) } // 🤔 : Still need to validate the content type. return JSON.parse(data: reply.data) }.then { json in return User(serialized: json) }.then { user in // Do something with the user object. }.fail { error in // Don’t handle errors like this when being outside of keynote. fatalError("FIXME: Handle error: (error)") }.done()
  • 3.
    URLSession + Promises typealiasReply = (response: URLResponse, data: Data) // I really don’t have a better name. protocol RESTful { func get(url: URL) -> Promise<Reply> }
  • 4.
  • 5.
    URLSession+Promise extension URLSession: RESTful{ func get(url: URL) -> Promise<Reply> { /* TODO: Use * URLSession.dataTask(with:, completionHandler:) */ fatalError("Unimplemented.") } } // Looks good, no?
  • 6.
    URLSession+Promise extension URLSession: RESTful{ func get(url: URL) -> Promise<Reply> { /* TODO: Use * URLSession.dataTask(with:, completionHandler:) */ fatalError("Unimplemented.") } } // Looks good, no? No.
  • 7.
    How to Test? extensionURLSession: RESTful { func get(url: URL) -> Promise<Reply> { /* TODO: Use * URLSession.dataTask(with:, completionHandler:) */ fatalError("Unimplemented.") } } // Looks good, no? No, I don’t want to set up an HTTP server.
  • 8.
    Let’s try again protocolURLSessionLike { typealias Completion = (Data?, URLResponse?, Error?) -> Void func dataTask(with url: URL, completionHandler: @escaping Completion) -> URLSessionDataTask } extension URLSession: URLSessionLike {}
  • 9.
    Let’s try again(cont.) protocol URLSessionLike: RESTful { typealias Completion = (Data?, URLResponse?, Error?) -> Void func dataTask(with url: URL, completionHandler: @escaping Completion) -> URLSessionDataTask } extension URLSession: URLSessionLike {}
 
 extension URLSessionLike { func get(url: URL) -> Promise<Reply> { fatalError("Still unimplemented.") } }
  • 10.
    Testing the Protocol classMockSession: URLSessionLike { internal func dataTask(with url: URL, completionHandler: @escaping URLSessionLike.Completion) -> URLSessionDataTask { DispatchQueue.main.async { let error = URLError(.notConnectedToInternet) completionHandler(nil, nil, error) } } } /* Later you will only mock RESTful things and return * Promises directly. */
  • 11.
    Questions? Slides will beuploaded and linked in the Meetup Group