如何使用Codable协议在swift中构建json对象模型

时间:2017-10-17 19:42:02

标签: json swift codable

我正在编写一个REST Web应用程序客户端,我使用的JSON看起来像这样:

JSON1

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

  "owner" : "Steve"
}

但API也可以给我这种JSON

JSON2

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

  "latitude" : 3.1415926535
  "longitude" : 2.7182818284
}

所以现在在我的应用程序中,我创建了一个符合Codable协议的结构

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
}

这种架构有效但在我看来并不是最好的或优雅的。你知道一个更好的方法吗? 存在?我应该使用2个不同的json模型,而不是:

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
}

我是REST API客户端的新手,这种JSON似乎没有使用好的架构。

1 个答案:

答案 0 :(得分:1)

制作ownerlatitude& longitude属性可选。 并使用decodeIfPresent仅在属性存在时对其进行解码。

您可以创建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)
    }
}

示例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)!.

用法:

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