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

Embrace Immutability

Keith Smiley
February 15, 2016

Embrace Immutability

Keith describes an open source library for parsing JSON written at Lyft, how it enables you to use immutable model objects, and why that's a good thing.

Keith Smiley

February 15, 2016
Tweet

More Decks by Keith Smiley

Other Decks in Programming

Transcript

  1. struct User: Mappable { var id: String? var photoURL: NSURL?

    var verified: Bool = true init() {} mutating func map(mapper: Mapper) { id « mapper["id"] photoURL « mapper["photoURL"] verified « mapper["phone.verified"] } }
  2. protocol Mapper { func baseType<T>(field: T?) -> T? func baseTypeArray<T>(field:

    [T]?) -> [T]? // ... subscript(keyPath: String) -> Mapper { get } }
  3. func « <T>(inout left: T?, mapper: Mapper) { left =

    mapper.baseType(left) } func « <T>(inout left: [T]?, mapper: Mapper) { left = mapper.baseTypeArray(left) }
  4. class MapperFromJSON: Mapper { var JSON: NSDictionary var currentValue: AnyObject?

    // ... subscript(keyPath: String) -> Mapper { get { self.currentValue = self.JSON.valueForKeyPath(keyPath) return self } } }
  5. func baseType<T>(field: T?) -> T? { let value = self.currentValue

    switch T.self { case is NSURL.Type where value is String: return NSURL(string: value as! String) as? T // ... default: return value as? T } }
  6. case is CLLocationCoordinate2D.Type: if let castedValue = value as? [String:

    Double], let latitude = castedValue["lat"], let longitude = castedValue["lng"] { return CLLocationCoordinate2D(latitude: latitude, longitude: longitude) as? T } return nil
  7. struct User: Mappable { let id: String let photoURL: NSURL?

    let verified: Bool init(map: Mapper) throws { try id = map.from("id") photoURL = map.optionalFrom("photoURL") verified = map.optionalFrom("phone.verified") ?? false } }
  8. func from<T>(field: String) throws -> T { if let value

    = self.JSONFromField(field) as? T { return value } throw MapperError() }
  9. extension NSURL: Convertible { static func fromMap(value: AnyObject?) throws ->

    NSURL { if let string = value as? String, let URL = NSURL(string: string) { return URL } throw MapperError() } }
  10. struct AppInfo { let hints: [HintID: Hint] init(map: Mapper) throws

    { try hints = map.from("hints", transformation: Transform.toDictionary { $0.id }) } }
  11. func from<T>(field: String, transformation: AnyObject? throws -> T) rethrows ->

    T { return try transformation(self.JSONFromField(field)) }
  12. DUMB MODELS struct User: Mappable { let id: String let

    photoURL: NSURL? init(map: Mapper) throws { try id = map.from("id") photoURL = map.optionalFrom("photoURL") } }
  13. 1. How can I do this? 2. How can I

    do this easier? 3. How can I do this simpler? 4. How can I not do this?