Skip to content

Instantly share code, notes, and snippets.

@cipriantarta
Last active September 12, 2017 12:00
Show Gist options
  • Save cipriantarta/75541ce2391975ef921aa8722e9dc76e to your computer and use it in GitHub Desktop.
Save cipriantarta/75541ce2391975ef921aa8722e9dc76e to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import UIKit
typealias JSON = [String: Any]
protocol APIModelProtocol {
init?(_ data: JSON)
}
protocol APISerializerProtocol {
associatedtype APIModelType
func serialize(_ model: APIModelType) -> JSON
func deserialize(_ data: JSON) -> APIModelType
}
private class _AnyAPISerializer<T>: APISerializerProtocol {
typealias APIModelType = T
init() {
guard type(of: self) != _AnyAPISerializer.self else {
fatalError("_AnyAPISerializer<APIModelType> instances can not be created; create a subclass instance instead")
}
}
func serialize(_ model: T) -> JSON {
fatalError("Must override")
}
func deserialize(_ data: JSON) -> T {
fatalError("Must override")
}
}
private class _AnyAPISerializerBox<T: APISerializerProtocol>: _AnyAPISerializer<T.APIModelType> {
private let base: T
init(_ base: T) {
self.base = base
}
override func serialize(_ model: T.APIModelType) -> JSON {
return base.serialize(model)
}
override func deserialize(_ data: JSON) -> T.APIModelType {
return base.deserialize(data)
}
}
class AnyAPISerializer<APIModelType>: APISerializerProtocol {
private let box: _AnyAPISerializer<APIModelType>
init<Concrete: APISerializerProtocol>(_ concrete: Concrete) where Concrete.APIModelType == APIModelType {
box = _AnyAPISerializerBox(concrete)
}
func serialize(_ model: APIModelType) -> JSON {
return box.serialize(model)
}
func deserialize(_ data: JSON) -> APIModelType {
return box.deserialize(data)
}
}
//================================================
class MyModel: APIModelProtocol {
var name: String?
required init!(_ data: JSON) {
self.name = data["name"] as? String
}
}
class MyModelSerializer: APISerializerProtocol {
typealias APIModelType = MyModel
func serialize(_ model: MyModel) -> JSON {
return ["name": model.name!]
}
func deserialize(_ data: JSON) -> MyModel {
return MyModel(data)
}
}
class APIResponse {
private let data: Data
init(_ data: Data) {
self.data = data
}
func json(_ serializer: AnyAPISerializer<Any>) -> APIModelProtocol? {
guard let obj = try? JSONSerialization.jsonObject(with: self.data), let result = obj as? APIModelProtocol else {
return nil
}
return result
}
}
let serializer = AnyAPISerializer(MyModelSerializer())
let response = APIResponse(data)
let data = try! JSONSerialization.data(withJSONObject: ["name": "Test"])
response.json(serializer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment