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

Anthony Levings | JSON, Swift and Type Safety: ...

Anthony Levings | JSON, Swift and Type Safety: It's a wrap

Presented at www.swiftsummit.com

Swift Summit

March 21, 2015
Tweet

More Decks by Swift Summit

Other Decks in Programming

Transcript

  1. { "JSON, Swift and Type Safety" : "It's a wrap"

    } @gylphi @sketchytech [Anthony Levings, @sketchyTech] Presented at SwiftSummit.com, 21 March 2015
  2. JSON (JavaScript Object Notation) is a lightweight data-interchange format. It

    is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.
  3. var error:NSError? if let jsonObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error:

    &error) as? [String: AnyObject] { let count = jsonObject["resultCount"] as? Int // casting value to Int }
  4. var error:NSError? if let jsonObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error:

    &error) as? [String: AnyObject] { var jDict = jsonObject jDict["resultCount"] = "string" // change of type can happen easily let jsonData = NSJSONSerialization.dataWithJSONObject(jDict, options: nil, error: nil) }
  5. then you can simply write if let dict = jsonObject

    as? Dictionary<String,String> { } or this if let dict = jsonObject as? [Int] { } to achieve type safety, but this will rarely the case in the real world and so rather than keep dreaming, we have…
  6. enum Value { // enum cases case StringType(String) case NumberType(NSNumber)

    case NullType(NSNull) // collection types case DictionaryType(Dictionary<String,Value>) case ArrayType([Value]) }
  7. And we then wrap each value of a received [AnyObject]

    or [String: AnyObject] as the initializer to our enum* * working code available, ask me after if you’re interested
  8. if let num = dictionary["key"]?.number { } RATHER THAN THIS:

    if let dict = jsonObj as? [String: AnyObject], str = dict[“key”] as? NSNumber { } We can then combine associated values with computed variables to achieve this kind of syntax:
  9. Argo  (thoughtbot)   Swiftz  (typelift) json-­‐swift  (David  Owens  II) Three

    GitHub Swift–JSON libraries that already use associated value enums in their code:
  10. Type Safety = Empowerment • restrict  changes  of  type  (e.g.

      through  subscripting)   • prevent the return of AnyObject • enable the compiler to better detect errors and assist the programmer • reduction in the amount of code to test types and return values • IT MAKES US THINK ABOUT TREATMENT OF JSON!
  11. The larger your model object, the longer the build takes

    [using Argo]. This is an issue with the Swift compiler having trouble working out all the nested type inference. While Argo works, it can be impracticle for large objects. There is work being done on a separate branch to reduce this time. (Tony DiPasquale, thoughtbot) https://robots.thoughtbot.com/parsing-embedded-json-and-arrays-in-swift Argo
  12. enum Value { // enum cases case StringType(String) case NumberType(NSNumber)

    case NullType(NSNull) // collection types case DictionaryType(JSONDictionary) case ArrayType(JSONArray) }
  13. if let p = parsedJSON["results"]?.jsonArr, d = p[0]?.jsonDict { d["trackName"]?.str

    } If we use a struct and an enum together we can use leverage stored values: (1) the getter can wrap individual values on demand (not in advance). (2) changes and additions to stored values become simplified parsedJSON["results"]?[0]?["trackName"] = "Something" And setting: Getting:
  14. Using the struct approach we also have easier access to

    information like which keys have String values, which have Number values, etc. —- Dictionary —- json.keysWithNumberValues json.keysWithStringValues —- Array ——- json.isNumberArray json.isStringArray json.isMixedArray json.removeAllNumbers() json.removeAllStrings() and other benefits of stored properties, which enums don’t enjoy.
  15. if let url = NSURL(string:"http://itunes.apple.com/search? term=b12&limit=40"), data = NSData(contentsOfURL: url),

    parsedJSON = JSONParser.parseDictionary(data), iTD = iTunesData(dict: parsedJSON) { let tracks = map(iTD.results, {x in Track(dict:x.jsonDict)}) } Bespoke Handling of Data