2017-10-17 63 views
1

我編碼一個REST的Web應用程序客戶端,我使用JSON看起來像這樣:如何架構迅速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 
} 

所以,現在在我的應用程序創建一個struct誰符合可編程協議

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

我會用1層結構,然後使用選配的值是沒有在兩個ison結構之間共享,就像你在第一個例子中所做的那樣 – Marcel

回答

1

使ownerlatitude & longitude屬性可選。 並使用decodeIfPresent僅當它們存在時才解碼屬性。

您可以創建一個struct原樣

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