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

Parsing JSON in Swift

Anat Gilboa
September 01, 2016

Parsing JSON in Swift

Given at try! Swift NYC on September 1, 2016.
http://www.tryswiftnyc.com

Anat Gilboa

September 01, 2016
Tweet

More Decks by Anat Gilboa

Other Decks in Technology

Transcript

  1. Currying struct User { let id: Int let name: String

    let age: Int } static func create(id: Int)(name: String)(age: Int) -> User { return User(id: id, name: name, age: age) }
  2. The Proposal: Result Result<Value, Error> typealias JSONObject = [String:AnyObject] enum

    JSONError : ErrorType { case NoSuchKey(String) case TypeMismatch } func stringForKey(json: JSONObject, key: String) -> Result<String, JSONError> { guard let value = json[key] else { return .Failure(.NoSuchKey(key)) } if let value = value as? String { return .Success(value) } else { return .Failure(.TypeMismatch) } }
  3. The Proposal: Result Result<Value, Error> typealias JSONObject = [String:AnyObject] enum

    JSONError : ErrorType { case NoSuchKey(String) case TypeMismatch } func stringForKey(json: JSONObject, key: String) -> Result<String, JSONError> { guard let value = json[key] else { return .Failure(.NoSuchKey(key)) } if let value = value as? String { return .Success(value) } else { return .Failure(.TypeMismatch) } }
  4. No Library, No Problem? struct User { let id: Int

    let name: String let age: Int }
  5. if-let it up let user: User? if let user =

    json["user"] as? [String: String] { if let id = user["id"] { if let name = user["name"] { if let age = user["age"] { user = User(id, name: name, age: age) } } } }
  6. guard? let user: User? guard let user = json["user"] as?

    [String: String] { if let id = user["id"], name = user["name"], age = user["age"] { user = User(id, name: name, age: age) } } else { return nil }
  7. How ‘bout do-catch? 4 Good for many trys in sequence

    4 Don't forget to mark the function that is throwing
  8. The Goal 1. Look into different mapping libraries to see

    their interfaces 2. Take into account the simplicity of the respective APIs
  9. The Subjects Alembic Argo Arrow CaesarParser Decodable Elevate Freddy Genome

    Gloss JSON mapper ObjectMapper SwiftyJSON Tailor Tyro Unbox
  10. Example: SwiftyJSON import SwiftyJSON struct User { let id: Int

    let name: String let age: Int } let json = JSON(["id":2378, "name":"Jack", "age": 23]) if let name = json["name"].string { // Do a thing } else { print(json["name"].error) }
  11. Example: SwiftyJSON public let ErrorUnsupportedType: Int = 999 public let

    ErrorIndexOutOfBounds: Int = 900 public let ErrorWrongType: Int = 901 public let ErrorNotExist: Int = 500 public let ErrorInvalidJSON: Int = 490
  12. Example: Mapper import Mapper struct User { ... } extension

    User : Mappable { init(map: Mapper) throws { try id = map.from("id") try name = map.from("name") age = map.optionalFrom("age") } }
  13. Example: Mapper public enum MapperError: ErrorType { case ConvertibleError(value: AnyObject?,

    type: Any.Type) case CustomError(field: String?, message: String) case InvalidRawValueError(field: String, value: Any, type: Any.Type) case MissingFieldError(field: String) case TypeMismatchError(field: String, value: AnyObject, type: Any.Type) }
  14. Example: Freddy import Freddy struct User { ... } extension

    User: JSONDecodable { public init(json value: JSON) throws { id = try value.int("id") name = try value.string("name") age = try value.int("age") } }
  15. Example: Freddy public enum Error: ErrorType { case IndexOutOfBounds(index: Swift.Int)

    case KeyNotFound(key: Swift.String) case UnexpectedSubscript(type: JSONPathType.Type) case ValueNotConvertible(value: JSON, to: Any.Type) }
  16. Example: Decodable import Decodable struct User { ... } extension

    User: Decodable { static func decode(j: Any) throws -> User { return try User( id: j => "id", name: j => "name", age: j => "age" ) } }
  17. Example: Decodable public enum DecodingError: ErrorProtocol, Equatable { case typeMismatch(expected:

    Any.Type, actual: Any.Type, Metadata) case missingKey(String, Metadata) case rawRepresentableInitializationError(rawValue: Any, Metadata) case other(ErrorProtocol, Metadata) }
  18. Example: Argo import Argo import Curry import Result struct User

    { let id: Int let name: String let age: Int? } extension User: Decodable { static func decode(j: JSON) -> Decoded<User> { return curry(User.init) <^> j <| "id" <*> j <| "name" <*> j <|? "age" } }
  19. Further Reading http://bit.ly/tryJSON 1. Efficient JSON in Swift with Functional

    Concepts and Generics 2. Real World JSON Parsing with Swift 3. Parsing Embedded JSON and Arrays in Swift (H/T Tony DiPasquale)
  20. Thanks! 4 Community members: Matt Diephouse, Soroush Khanlou, Matt Bischoff

    4 Amex friends 4 Your awesome JSON decoding libraries!