zoul / Generic Json Swift
Programming Languages
Labels
Projects that are alternatives of or similar to Generic Json Swift
Generic JSON
Generic JSON makes it easy to deal with freeform JSON strings without creating a separate, well-typed structure.
Codable and freeform JSON
Swift 4 introduced a new JSON encoding and decoding machinery represented by the Codable
protocol. The feature is very nice and very type-safe, meaning it’s no longer possible to just willy-nilly decode a JSON string pulling random untyped data from it. Which is good™ most of the time – but what should you do when you do want to just willy-nilly encode or decode a JSON string without introducing a separate, well-typed structure for it? For example:
// error: heterogeneous collection literal could only be inferred to '[String : Any]';
// add explicit type annotation if this is intentional
let json = [
"foo": "foo",
"bar": 1,
]
// Okay then:
let json: [String:Any] = [
"foo": "foo",
"bar": 1,
]
// But: fatal error: Dictionary<String, Any> does not conform to Encodable because Any does not conform to Encodable.
let encoded = try JSONEncoder().encode(json)
So this doesn’t work very well. Also, the json
value can’t be checked for equality with another, although arbitrary JSON values should support equality. Enter JSON
.
Usage
JSON
structure
Create a let json: JSON = [
"foo": "foo",
"bar": 1,
]
// "{"bar":1,"foo":"foo"}"
let str = try String(data: try JSONEncoder().encode(json), encoding: .utf8)!
let hopefullyTrue = (json == json) // true!
Encodable
objects into a generic JSON structure
Convert struct Player: Codable {
let name: String
let swings: Bool
}
let val = try JSON(encodable: Player(name: "Miles", swings: true))
val == [
"name": "Miles",
"swings": true,
] // true
Query Values
Consider the following JSON
structure:
let json: JSON = [
"num": 1,
"str": "baz",
"bool": true,
"obj": [
"foo": "jar",
"bar": 1,
]
]
Querying values can be done using optional property accessors, subscripting or dynamic member subscripting:
// Property accessors
if let str = json.objectValue?["str"]?.stringValue { … }
if let foo = json.objectValue?["obj"]?.objectValue?["foo"]?.stringValue { … }
// Subscripting
if let str = json["str"]?.stringValue { … }
if let foo = json["obj"]?["foo"]?.stringValue { … }
// Dynamic member subscripting
if let str = json.str?.stringValue { … }
if let foo = json.obj?.foo?.stringValue { … }
You may even drill through nested structures using a dot-separated key path:
let val = json[keyPath: "obj.foo"] // "jar"