CocoaPods trunk is moving to be read-only. Read more on the blog, there are 13 months to go.
| TestsTested | ✗ |
| LangLanguage | SwiftSwift |
| License | MIT |
| ReleasedLast Release | May 2017 |
| SwiftSwift Version | 3.0 |
| SPMSupports SPM | ✗ |
Maintained by Alex Hmelevski.
AHJSONSerializer is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from JSON.
To support json decoding, a class or struct just needs to implement the JSONDecodable protocol:
public protocol JSONDecodable {
init(decoder: AHJSONDecoder)
}To support json encoding, a class or a struct need to implement the JSONEncodable protocol:
public protocol JSONEncodable {
func encode(with encoder: AHJSONEncoder)
}AHJSONSerializer uses the <~ and “~>”` syntaxic sugar operators to define how each member variable maps to and from JSON.
class User: JSONDecodable,JSONEncodable {
var username: String?
var age: Int?
var weight: Double!
var array: [AnyObject]?
var dictionary: [String : AnyObject] = [:]
var bestFriend: User? // Nested User object
var friends: [User]? // Array of Users
var birthday: Date?
required init(decoder: AHJSONDecoder) {
username <~ decoder["username"]
age <~ decoder["age"]
weight <~ decoder["weight"]
array <~ decoder["arr"]
dictionary <~ decoder["dict"]
bestFriend <~ decoder["best_friend"]
friends <~ decoder["friends"]
birthday <~ decoder["birthday"]
}
func encode(with encoder: AHJSONEncoder) {
username ~> encoder["username"]
age ~> encoder["age"]
weight ~> encoder["weight"]
array ~> encoder["arr"]
dictionary ~> encoder["dict"]
bestFriend ~> encoder["best_friend"]
friends ~> encoder["friends"]
birthday ~> encoder["birthday"]
}
}
struct Temperature: JSONDecodable {
let celsius: Double
let fahrenheit: Double?
init(decoder: AHJSONDecoder) {
celsius = decoder["temp_in_c"].value() ?? 0.0
fahrenheit = decoder["temp_in_f"].value()
}
}Once your class implements JSONDecodable and JSONEncodable, AHJSONSerializer allows you to easily convert to and from JSON.
Convert a JSON string to a model object:
let user = Object(json: dictionary)Convert a model object to a JSON dictionary:
let json = user.jsonAHJSONSerializer can map classes composed of the following types:
IntBoolDoubleFloatStringRawRepresentable (Enums)Array<AnyObject>Dictionary<String, AnyObject>Object<T: JSONDecodable>Array<T: JSONDecodable>Array<Array<T: JSONDecodable>>Set<T: JSONDecodable>Dictionary<String, T: JSONDecodable>Dictionary<String, Array<T: JSONDecodable>>JSONDecodable Protocolinit(decoder: AHJSONDecoder) This function is where all mapping definitions should go. When parsing JSON, this function is executed during object creation. When generating JSON, it is the only function that is called on the object.
JSONEncodable Protocolinit(decoder: AHJSONEncoder) This function is where all encoding definitions should go. The function will be used when Object.json will be called
AHJSONSerializer supports dot notation within keys for easy mapping of nested objects. Given the following JSON String:
"distance" : {
"text" : "102 ft",
"value" : 31
}You can access the nested objects as follows:
func init(decoder: AHJSONDecoder) {
distance <~ map["distance.value"]
}AHJSONSerializer supports map function so you can do crazy stuff like:
struct Car: JSONDecodable, JSONEncodable {
let model: String
init(decoder: AHJSONDecoder) {
model = decoder["model"].map(transform: transformToInt)
.map(transform: increase)
.map(transform: transformToString)
.value() ?? ""
}
func encode(with encoder: AHJSONEncoder) {
model ~> encoder["firstName"].map{uppercased}
}
private func uppercased(str: String) -> String {
return str.uppercased()
}
}
*map function should be strong typed (no generics)
Classes that implement the JSONDecodable and JSONEncodable protocols can easily be subclassed. When subclassing mappable classes, follow the structure below:
class Base: JSONDecodable {
var base: String?
required init(decoder: AHJSONDecoder) {
base <~ map["base"]
}
}
class Subclass: Base {
var sub: String?
override init(decoder: AHJSONDecoder) {
super.init(decoder)
sub <~ map["sub"]
}
}Make sure your subclass implemenation calls the right initializers and mapping functions to also apply the mappings from your superclass.
AHJSONSerializer can handle classes with generic types as long as the generic type also conforms to JSONDecodable. See the following example:
class Result<T: JSONDecodable>: JSONDecodable {
var result: T?
required init(decoder: AHJSONDecoder) {
result <~ map["result"]
}
}
Contributions are very welcome
Before submitting any pull request, please ensure you have run the included tests and they have passed. If you are including new functionality, please write test cases for it as well.
To add AHJSONSerializer to a Swift Package Manager based project, add:
.Package(url: "hhttps://github.com/AlexHmelevski/AHJSONSerializer.git", majorVersion: 2, minor: 2),to your Package.swift files dependencies array.
Alexei Hmelevski, [email protected]
AHJSONSerializer is available under the MIT license. See the LICENSE file for more info.