Вот библиотека TypePreservingCodingAdapter, чтобы сделать просто что (может быть установлен с Cocoapods или SwiftPackageManager).
код ниже компилирует и работает просто великолепно с Swift 4.2
. К сожалению для каждого подкласса необходимо будет реализовать кодирование и декодирование свойств самостоятельно.
import TypePreservingCodingAdapter
import Foundation
// redeclared your types with initializers
class Server: Codable {
var id: Int?
init(id: Int?) {
self.id = id
}
}
class Development: Server {
var name: String?
var userId: Int?
private enum CodingKeys: String, CodingKey {
case name
case userId
}
init(id: Int?, name: String?, userId: Int?) {
self.name = name
self.userId = userId
super.init(id: id)
}
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decodeIfPresent(String.self, forKey: .name)
userId = try container.decodeIfPresent(Int.self, forKey: .userId)
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(userId, forKey: .userId)
}
}
// create and adapter
let adapter = TypePreservingCodingAdapter()
let encoder = JSONEncoder()
let decoder = JSONDecoder()
// inject it into encoder and decoder
encoder.userInfo[.typePreservingAdapter] = adapter
decoder.userInfo[.typePreservingAdapter] = adapter
// register your types with adapter
adapter.register(type: Server.self).register(type: Development.self)
let server = Server(id: 1)
let development = Development(id: 2, name: "dev", userId: 42)
let servers: [Server] = [server, development]
// wrap specific object with Wrap helper object
let data = try! encoder.encode(servers.map { Wrap(wrapped: [110]) })
// decode object back and unwrap them force casting to a common ancestor type
let decodedServers = try! decoder.decode([Wrap].self, from: data).map { [110].wrapped as! Server }
// check that decoded object are of correct types
print(decodedServers.first is Server) // prints true
print(decodedServers.last is Development) // prints true