From 586bb44e20b97734da4f6247f156e7d9436df862 Mon Sep 17 00:00:00 2001 From: Jonas Rathert Date: Fri, 10 Aug 2018 20:36:58 +0200 Subject: [PATCH 1/2] Converted to Xcode 9.4.1 / Swift 4.1.2 Mainly some type conversions (get rid of NS*), rename of functions, syntactical sugar etc. --- Networking.playground/Contents.swift | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Networking.playground/Contents.swift b/Networking.playground/Contents.swift index 719027f..14ba876 100644 --- a/Networking.playground/Contents.swift +++ b/Networking.playground/Contents.swift @@ -5,12 +5,12 @@ //: It will serve up the current directory, so make sure to be in the directory containing episodes.json import UIKit -import XCPlayground +import PlaygroundSupport typealias JSONDictionary = [String: AnyObject] -let url = NSURL(string: "http://localhost:8000/episodes.json")! +let url = URL(string: "http://localhost:8000/episodes.json")! struct Episode { @@ -21,7 +21,7 @@ struct Episode { extension Episode { init?(dictionary: JSONDictionary) { guard let id = dictionary["id"] as? String, - title = dictionary["title"] as? String else { return nil } + let title = dictionary["title"] as? String else { return nil } self.id = id self.title = title } @@ -32,15 +32,15 @@ struct Media {} struct Resource { - let url: NSURL - let parse: NSData -> A? + let url: URL + let parse: (Data) -> A? } extension Resource { - init(url: NSURL, parseJSON: AnyObject -> A?) { + init(url: URL, parseJSON: @escaping (Any) -> A?) { self.url = url self.parse = { data in - let json = try? NSJSONSerialization.JSONObjectWithData(data, options: []) + let json = try? JSONSerialization.jsonObject(with: data, options: []) return json.flatMap(parseJSON) } } @@ -50,14 +50,14 @@ extension Resource { extension Episode { static let all = Resource<[Episode]>(url: url, parseJSON: { json in guard let dictionaries = json as? [JSONDictionary] else { return nil } - return dictionaries.flatMap(Episode.init) + return dictionaries.compactMap(Episode.init) }) } final class Webservice { - func load(resource: Resource, completion: (A?) -> ()) { - NSURLSession.sharedSession().dataTaskWithURL(resource.url) { data, _, _ in + func load(resource: Resource, completion: @escaping (A?) -> ()) { + URLSession.shared.dataTask(with: resource.url) { data, _, _ in guard let data = data else { completion(nil) return @@ -68,8 +68,8 @@ final class Webservice { } -XCPlaygroundPage.currentPage.needsIndefiniteExecution = true +PlaygroundPage.current.needsIndefiniteExecution = true -Webservice().load(Episode.all) { result in - print(result) +Webservice().load(resource: Episode.all) { result in + print(result ?? "") } From 63829ed1b2005b6695ce6c0e4559e3e12d954245 Mon Sep 17 00:00:00 2001 From: Jonas Rathert Date: Fri, 10 Aug 2018 20:51:29 +0200 Subject: [PATCH 2/2] Use new JSONDecoder capabilities introduced with Swift 4 This simplifies the code a lot, as the parse closure is in Resources is (almost) independent of the actual type, and we do not need any specific initialisers any more. Only requirement is to make use of the new Decodable protocol for all structures used in JSON API --- Networking.playground/Contents.swift | 29 ++++++++-------------------- README.md | 8 +++++++- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/Networking.playground/Contents.swift b/Networking.playground/Contents.swift index 14ba876..416b20b 100644 --- a/Networking.playground/Contents.swift +++ b/Networking.playground/Contents.swift @@ -8,50 +8,36 @@ import UIKit import PlaygroundSupport -typealias JSONDictionary = [String: AnyObject] - let url = URL(string: "http://localhost:8000/episodes.json")! -struct Episode { +struct Episode: Decodable { let id: String let title: String } -extension Episode { - init?(dictionary: JSONDictionary) { - guard let id = dictionary["id"] as? String, - let title = dictionary["title"] as? String else { return nil } - self.id = id - self.title = title - } -} +struct Media: Decodable {} -struct Media {} - -struct Resource { +struct Resource { let url: URL let parse: (Data) -> A? } + extension Resource { - init(url: URL, parseJSON: @escaping (Any) -> A?) { + init(url: URL) { self.url = url self.parse = { data in - let json = try? JSONSerialization.jsonObject(with: data, options: []) - return json.flatMap(parseJSON) + return try? JSONDecoder().decode(A.self, from: data) } } } extension Episode { - static let all = Resource<[Episode]>(url: url, parseJSON: { json in - guard let dictionaries = json as? [JSONDictionary] else { return nil } - return dictionaries.compactMap(Episode.init) - }) + static let all = Resource<[Episode]>(url: url) } @@ -73,3 +59,4 @@ PlaygroundPage.current.needsIndefiniteExecution = true Webservice().load(resource: Episode.all) { result in print(result ?? "") } + diff --git a/README.md b/README.md index 1172001..f95360c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ # Swift Talk ## Networking -This is the code that accompanies Swift Talk Episode 1: [Networking](https://talk.objc.io/episodes/S01E01-networking) \ No newline at end of file +This is the code that accompanies Swift Talk Episode 1: [Networking](https://talk.objc.io/episodes/S01E01-networking) + +It has been slightly adapted to work with Xcode 9 / Swift 4. + +* some syntactical and type changes +* use of new JSONDecoder(), which simplifies code lot - see [Apple documentation](https://developer.apple.com/documentation/foundation/jsondecoder) +