When would you use JSONSerialization instead of Codable, and what does the untyped route cost?
Predict first
What does this print?
let obj = try JSONSerialization.jsonObject(with: Data(#"{"a":null,"b":[1,2]}"#.utf8)) as! [String: Any]
print(obj["a"] is NSNull, obj["a"] as? String as Any, obj["b"] as? [Int] as Any)
- true nil Optional([1, 2])
- false nil Optional([1, 2])
- true Optional("") nil
Mental model. Codable pours the JSON into a mould you made. JSONSerialization gives you a heap of loose parts you must sort yourself.
JSONSerialization parses JSON into an untyped tree of Any: NSDictionary, NSArray, NSString, NSNumber and NSNull. It suits shapes you cannot model in a type (a dynamic schema, forwarding a payload, a quick script) and writing out an arbitrary dictionary. For known shapes, Codable is safer, because the compiler checks the types, and usually faster, because it builds your structs directly instead of an intermediate tree of boxed objects.
Know the untyped quirks: JSON null arrives as NSNull, not nil, so as? String on it gives nil and an optional-chain hides the difference; numbers are NSNumber. For big payloads, decode off the main thread, declare only the fields you need (extra keys are ignored), and remember there is no streaming parser: very large feeds are better sent as newline-delimited JSON and parsed line by line.
A JSON null is the object NSNull: present, but not a string. The numbers bridge to [Int] as expected.
Common traps
- Treating
nullas a missing key. It is a present value,NSNull. - Optimising by switching to
JSONSerializationwithout measuring. The untyped tree allocates more, not less.
They might follow up with
- How do you keep a flexible part of a typed model? Decode that field as a small enum or a custom
JSONValuetype, notAny. - Does a decoder instance cost much to create? No. Configure one per use, or share a configured one you do not mutate.
Related questions
- 2.5.4 How do you read a DecodingError, and how do you decode tolerantly?
- 2.9.2 Why does NSNumber confuse Bool, Int and Double, and how do you read untyped values safely?
← How do you read a DecodingError, and how do you decode tolerantly? What is a property list, and where do you meet one? →