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.
- Features
- The Basics
- Mapping Nested Objects
- Subclassing
- Generic Objects
- To Do
- Contributing
- Installation
- Mapping JSON to objects (classes,structs)
- Mapping objects (classes,structs) to JSON
- Nested Objects
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>>- Optionals of all the above
- Implicitly Unwrapped Optionals of the above
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.
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"]
}
}- reduce number of methods for value casting
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.
AHJSONSerializer is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod "AHJSONSerializer"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, alexei.hmelevski@gmail.com
AHJSONSerializer is available under the MIT license. See the LICENSE file for more info.