protocol oriented json parsing in swift
TRANSCRIPT
JSON Parsingby JaSON Larsen@jarsen
JSON Parsingby JaSON Larsen@jarsen
JSON Value Extractionby JaSON Larsen@jarsen
The History
In the beginning...if let id = json["id"] as? Int { if let name = json["name"] as? String { if let email = json["email"] as? String { // create user } }}
Swift 1.2if let id = json["id"] as? Int, name = json["name"] as? String, email = json["email"] as? String { // create user}else { // return some error, ex: `Result<T>`}
Swift 2guard let id = json["id"] as? Int, name = json["name"] as? String, email = json["email"] as? String { // throw some error}
// create user
Argoextension User: Decodable { static func decode(j: JSON) -> Decoded<User> { return curry(User.init) // used to have to make a separate `make` function <^> j <| "id" <*> j <| "name" <*> j <|? "email" // Use ? for parsing optional values <*> j <| "role" // Custom types that also conform to Decodable just work <*> j <| ["company", "name"] // Parse nested objects <*> j <|| "friends" // parse arrays of objects }}
(https://github.com/thoughtbot/Argo)
What You Think
What Your Team Thinks
JSON Arrays...var pets = [Pet]()if let petsObjects = json["pets"] as? [JSONObject] { for petObject in petsObjects { guard let id = petObject["id"] as? Int, name = petObject["name"] as? String else { continue // or throw error if less tolerant } let pet = Pet(id: id, name: name) pets.append(pet) }}
Why so much work?
Wouldn't it be great if...struct User : JSONObjectConvertible { let id: Int let name: String let email: String? let pets: [Pet]
init(json: JSONObject) throws { id = try json.valueForKey("id") name = try json.valueForKey("name") email = try json.valueForKey("email") pets = try json.valueForKey("pets") }}
The Implementation
Playground Gisthttps://gist.github.com/jarsen/672aa5969689c5864cac
Caveat: Core Data ModelsFor NSManagedObject subclasses JSONObjectConvertible won't really work because init is not so simple...
public protocol JSONDecoding { func update(json: JSONObject) throws}
Caveat: Core Data Modelsclass User: NSManagedObject, JSONDecoding { @NSManaged var name: String @NSManaged var email: String
func update(json: JSONObject) throws { try name = json.valueForKey("name") try email = json.valueForKey("email") }}
Matthew Cheok's JSONCodableextension User: JSONEncodable { func toJSON() throws -> AnyObject { return try JSONEncoder.create({ (encoder) -> Void in try encoder.encode(id, key: "id") try encoder.encode(name, key: "full_name") try encoder.encode(email, key: "email") try encoder.encode(company, key: "company") try encoder.encode(friends, key: "friends") }) }}
(https://github.com/matthewcheok/JSONCodable)
Special Thanks» Bart Whiteley
» Brian Mullen
» BJ Homer
» Derrick Hathaway
» Dave DeLong
» Mark Schultz
» Tim Shadel
Resources» My blog jasonlarsen.me (look for No-Magic JSON
series)
» JaSON https://github.com/jarsen/JaSON
» JaSON (extension on Dictionary) https://github.com/bwhiteley/JaSON