1

I’m coding a REST Web app client and I use JSON which looks like this:

JSON1

{
  "device" : "iPhone"
  "manufacturer" : "Apple"
  "id" : 42

  "owner" : "Steve"
}

But the API could give me this kind of JSON also

JSON2

{
  "device" : "iPhone"
  "manufacturer" : "Apple"
  "id" : 42

  "latitude" : 3.1415926535
  "longitude" : 2.7182818284
}

So now in my app I create a struct who conforms to the Codable protocol

struct MyStruct : Codable {
  var name: String
  var manufacturer: String

  var owner: String?

  // I prefer to use a property of type Location rather than 2 variables
  var location: Location? {
    guard let latitude = latitude, let longitude = longitude else {
      return nil
    }

    return Location(latitude: latitude, longitude: longitude)
  }

  // Used to conform to the Codable protocol
  private var latitude: Double?
  private var longitude: Double?
}

struct Location {
  var latitude: Double = 0.0
  var longitude: Double = 0.0
}

This architecture works but it seems to me not the best one or elegant. Would you know if a better approach exists? Should I use 2 differents json model instead like:

struct MyStruct1 : Codable {
  var name: String
  var manufacturer: String
  var owner: String
}

struct MyStruct2 : Codable {
  var name: String
  var manufacturer: String

  private var latitude: Double
  private var longitude: Double
}

I'm new to REST API client and this kind of JSON doesn't seems to use a good architecture.

1
  • 1
    I would use 1 structure and then use optionals for the values that are not shared between the two ison structures, like you did in the first example Commented Oct 17, 2017 at 21:15

1 Answer 1

1

Make the owner, latitude & longitude properties optional. And use decodeIfPresent for decoding properties only when they exists.

You can create a struct as-

struct UserData: Codable {//Confroms to Codable protocol
    var id: Int
    var device: String
    var manufacturer: String
    var owner: String? = nil//Making property optional
    var latitude: Double? = nil//Making property optional
    var longitude: Double? = nil//Making property optional
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        id = try values.decode(Int.self, forKey: .id)
        device = try values.decode(String.self, forKey: .device)
        manufacturer = try values.decode(String.self, forKey: .manufacturer)
        owner = try values.decodeIfPresent(String.self, forKey: .owner)
        latitude = try values.decodeIfPresent(Double.self, forKey: .latitude)
        longitude = try values.decodeIfPresent(Double.self, forKey: .longitude)
    }
}

Example Json:

    let jsonExample = """
 {
  "device" : "iPhone",
  "manufacturer" : "Apple",
  "id" : 42,
  "owner" : "Steve"
}
""".data(using: .utf8)!
    let jsonExample2 = """
 {
  "device" : "iPhone",
  "manufacturer" : "Apple",
  "id" : 42,
  "latitude" : 3.1415926535,
  "longitude" : 2.7182818284
}
""".data(using: .utf8)!.

Usage:

    //Decode struct using JSONDecoder
     let jsonDecoder = JSONDecoder()
            do {
                let modelResult = try jsonDecoder.decode(UserData.self,from: jsonExample2)
                print("owner is \(String(describing: modelResult.owner)) - latitude is \(String(describing: modelResult.latitude)) - longitude is \(String(describing: (modelResult.longitude)))")
            } catch {
                print(error)
            }
Sign up to request clarification or add additional context in comments.

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.