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?

1
  • You have to use two different structs or you have to write a custom initializer to distinguish the cases Commented Dec 21, 2017 at 19:24

2 Answers 2

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"
}
Sign up to request clarification or add additional context in comments.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.