58
задан 18 October 2017 в 21:03

1 ответ

Вот библиотека 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
3
ответ дан 1 November 2019 в 14:42

Другие вопросы по тегам:

Похожие вопросы: