具有多种结构的 JSONEncoder

JSONEncoder with multiple structures

嗨,我有多个 JSON 数据包,就像我在下面写的那样。

{
  "data" : {
    "lng" : 36.159999999999997,
    "lat" : 50.359999999999999,
    "accuracy" : 5
  },
  "header" : {
    "type" : "loc"
  }
}

还有这个

{
  "data" : {
    "time" : 15646565455,
    "tz" : "+2",
    "system" : 5
  },
  "header" : {
    "type" : "syn"
  }
}

我有我的数据包结构,它适用于一种数据包结构。但是如何将它用于多个数据包结构。

struct Packet : Codable {
    enum StructureType : String, Codable {
        case location = "loc"
        case synchronize = "syn"
    }

    enum Status: String, Codable {
        case  OK   = "OK"
        case  NOT   = "NOT"
    }

    struct Header: Codable {
        let type: StructureType
        let status: Status?
    }
    var header: Header

    struct Data : Codable {

        struct LocationStruct : Codable {
            var lng: Double
            var lat: Double
            var accuracy: Double
        }
        struct SynchronizationStruct: Codable {
            var time: Int
            var tz: String
            var locale: String
        }
    }
    var data: Data

}

现在我想编码 JSON 取决于我的数据

let dataHeader = Packet.Header.init(type: .location, action: nil, ID: nil, dataID: nil, status: nil)
        let dataData = Packet.Data.LocationStruct.init(lng: lng, lat: lat, accuracy: acc)
        let dataObject = Packet.init(header: dataHeader, data: dataData)

        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        let data = try! encoder.encode(dataObject)

如何做到这一点,或者我需要为每个数据包使用我的数据结构的其他结构?

我建议你创建 3 个结构。

  1. 主要有数据结构和头结构。

每个结构都必须符合 Codable 协议。

struct Structure: Codable {
    let data: Data
    let header: Header

    init(data: Data, header: Header) {
        self.data = data
        self.header = header
    }

    enum CodingKeys: String, CodingKey { case data, header }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeIfPresent(data, forKey: .data)
        try container.encodeIfPresent(header, forKey: .header)
    }

}


struct Data: Codable {
    let lng: Double?
    let lat: Double?
    let accuracy: Double?
    let time: Int?
    let tz: String?
    let system: Int?
}

struct Header: Codable {
    let type: String
}

let firstStructure = Structure(data: Data(lng: 36.159999999999997, lat: 50.359999999999999, accuracy: 5, time: nil, tz: nil, system: nil), header: Header(type: "loc"))

let secondStructure = Structure(data: Data(lng: nil, lat: nil, accuracy: nil, time: 15646565455, tz: "+2", system: 5), header: Header(type: "syn"))

let encoder = JSONEncoder()

let firstData = try? encoder.encode(firstStructure)
let secondData = try? encoder.encode(secondStructure)

print(String(data: firstData!, encoding: String.Encoding.ascii))
print(String(data: secondData!, encoding: String.Encoding.ascii))

如有任何问题,请随时填写。下次在您提出任何问题之前,请尝试 google 它。有很多解决此类问题的好教程。

Raywanderlich tutorial

我有两个主要模型对象的结构,LocationSynchronization。然后我将它们定义为符合某些协议,我们在协议中指定我们如何知道哪个 "header" 适用于哪种类型的有效负载。然后我会制作一个通用数据包,可以打包这两种可能的有效载荷:

enum PayloadType: String, Codable {
    case location = "loc"
    case synchronize = "syn"
}

protocol Payload: Codable {
    var payloadType: PayloadType { get }
}

struct Location: Payload {
    let lat: Double
    let long: Double
    let accuracy: Double
    let payloadType = PayloadType.location

    enum CodingKeys: String, CodingKey {
        case lat,long,accuracy
    }
}

struct Synchronization: Payload {
    let time: Int
    let tz: String
    let system: Int
    let payloadType = PayloadType.synchronize

    enum CodingKeys: String, CodingKey {
        case time, tz, system
    }
}

struct Packet<T: Payload>: Codable {
    let data: T
    let header: PayloadType

    init(payload: T) {
        data = payload
        header = payload.payloadType
    }
}

那么你可以这样做:

let location = Location(lat: 36.16, long: 50.36, accuracy: 5)
let packet = Packet(payload: location)

let json = try! encoder.encode(packet)

导致:

{
  "data" : {
    "lat" : 36.159999999999997,
    "long" : 50.359999999999999,
    "accuracy" : 5
  },
  "header" : "loc"
}

let location = Synchronization(time: 15646565455, tz: "+2", system: 5)
let packet = Packet(payload: location)

let json = try! encoder.encode(packet)

导致:

{
  "data" : {
    "system" : 5,
    "time" : 15646565455,
    "tz" : "+2"
  },
  "header" : "syn"
}