Easily load JSON objects and decode them into structs or classes. The json(atKeyPath:) function infers the type from the constant or variable definition to decode meaning no casting is needed. Both string keys and keypaths (keys separated by dots .) are supported when decoding JSON.
- Check out the
Example.playgroundinside theJSONUtilities.xcodeprojfor a working example
CocoaPods:
Add the line pod 'JSONUtilities' to your Podfile.
Carthage:
Add the line github "lucianomarisi/JSONUtilities" to your Cartfile.
Manual:
Add the files inside the Sources folder into your Xcode project.
Swift Package Manager:
Add the line .Package(url: "https://github.com/lucianomarisi/JSONUtilities", majorVersion: 3) to your Package.swift.
IntDoubleFloatStringBool[String: AnyObject]RawRepresentableenums
[Int][Double][Float][String][Bool][[String: AnyObject]][RawRepresentable]
e.g. if MyClass and MyStruct conform to JSONObjectConvertible protocol
MyClass- [
MyClass] MyStruct- [
MyStruct]
[String: JSONRawType][String: JSONObjectConvertible][String: JSONPrimitiveConvertible][String: RawRepresentable]
When decoding arrays or dictionaries an invalidItemBehaviour parameter can be passed which controls what happens when an error occurs while decoding child items
.removethis will simply remove the item from the array or dictionary. This is the default.failif any of the children encounter an error the whole array or dictionary decoding will fail. For optional properties this means the array or dictionary will return nil, and for non optional properties it will throw an error.value(T)Provide an alternative value.custom((DecodingError) -> InvalidItemBehaviour)Lets you specify the behaviour based on the specific DecodingError
let filename = "myjsonfile"
let dictionary: [String: AnyObject] = try JSONDictionary.from(filename: filename)let data: Data = ...
let dictionary: [String: AnyObject] = try JSONDictionary.from(jsonData: data)Consider a JSON object that represents a person:
{
"name" : "John Doe",
"age" : 24,
"weight" : 72.4
}let jsonDictionary = try JSONDictionary.from(filename: "person.json")
let name: String = try jsonDictionary.json(atKeyPath: "name")
let age: Int = try jsonDictionary.json(atKeyPath: "age")
let weight: Int = try jsonDictionary.json(atKeyPath: "weight")
let profession: String? = jsonDictionary.json(atKeyPath: "profession") // Optional decodingstruct Person { //OR class Person {
let name: String
let age: Int
let weight: Double
let profession: String?
init(jsonDictionary: JSONDictionary) throws {
name = try jsonDictionary.json(atKeyPath: "name")
age = try jsonDictionary.json(atKeyPath: "age")
weight = try jsonDictionary.json(atKeyPath: "weight")
profession = jsonDictionary.json(atKeyPath: "profession")
}
}Consider a company JSON object:
{
"name" : "Working name LTD.",
"employees": [
{
"name": "John Doe",
"age": 24,
"weight": 72.4
},
{
"name": "Jane Doe",
"age": 22,
"weight": 70.1
}
]
}The Company struct can decode an array of Person structs/classes by making Person conform to the JSONObjectConvertible protocol
struct Company {
let name: String
let employees: [Person]
init(jsonDictionary: JSONDictionary) throws {
name = try jsonDictionary.json(atKeyPath: "name")
employees = try jsonDictionary.json(atKeyPath: "employees")
}
}Any type can extend the JSONPrimitiveConvertible protocol in order to allow decoding. For example extending URL: Note that this extension come out of the box
:
extension URL: JSONPrimitiveConvertible {
public typealias JSONType = String
public static func from(jsonValue: String) -> Self? {
return self.init(string: jsonValue)
}
}
let urlDictionary = ["url": "www.google.com"]
let url: URL = try! urlDictionary.json(atKeyPath: "url") // www.google.comIt's also possible to have an array of JSONPrimitiveConvertible values, for example:
let urlsDictionary = ["urls": ["www.google.com", "www.yahoo.com"]]
let urls: [URL] = try! urlsDictionary.json(atKeyPath: "urls") // [www.google.com, www.yahoo.com]