0

Hi I have multiple JSON Packets like I wrote below.

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

and this one

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

I have structure for my packets and it worked for one structure of packets. But how to use it for multiple packets structures.

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

}

Now I want to encode JSON depends from my Data

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)

How to do that, or I need to use other structure of my data struct for each of packets?

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Stremovskyy
  • 452
  • 7
  • 18
  • You have to use two different structs or you have to write a custom initializer to distinguish the cases – vadian Dec 21 '17 at 19:24

2 Answers2

4

I'd have structures for the two main model objects, Location and Synchronization. I'd then define them to conform to some protocol where we specified how we know which "header" goes for which type of payload. And I'd then make a generic Packet that can package these two possible payloads:

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
    }
}

Then you can do:

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

let json = try! encoder.encode(packet)

resulting in:

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

or

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

let json = try! encoder.encode(packet)

Resulting in:

{
  "data" : {
    "system" : 5,
    "time" : 15646565455,
    "tz" : "+2"
  },
  "header" : "syn"
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

I recomende you to create 3 structures.

  1. The main going to have data structure and header structure.

Each structure has to conform to Codable protocol.

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))

enter image description here

Fill free to ask eny questions. Next time before you ask any question, try to google it. There is a lot of good tutorials for solving this kind of problems.

Raywanderlich tutorial

yerpy
  • 1,366
  • 3
  • 17
  • 44