2017-08-04 111 views
0

我知道我可以創建failable初始化爲我的模型類從JSON數據的初始化:如何從JSON初始化模型類的自定義類型的屬性

struct Person { 
    let firstName: String 
    let middleName: String? 

    init?(JSONData data:[String:AnyObject]) { 
     guard let firstName = data["firstName"] as? String else { return nil } 
     self.firstName = firstName 
     self.middleName = data["middleName"] as? String 
    } 
} 

但如果我有另一個屬性在Person這是另一個模型類的類型?例如:

struct Person { 
    let firstName: String 
    let car: Car 

    init?(JSONData data:[String: AnyObject]) { 
     guard let firstName = data["firstName"] as! String, 
      let car = data["car"] as! Car // this line doesn't work I guess 
     else {return nil} 
     self.firstName = firstName 
     self.car = car 
    } 

} 

汽車看起來是這樣的:

struct Car { 
    let year: Int 
    let brand: String 
} 

是什麼力量讓上面的JSON數據解析自定義類型Car工作failable初始化的正確方法?

例如JSON:

{「firstName」: 「John」, 
「car」: { 
     「year」: 2009, 
     「brand」: 「BMW」 
     }} 

回答

0

首先,你guard聲明沒有返回自選。將!更改爲?。其次,你應該將數據傳遞給初始化器並檢查它是否爲零。

guard let firstName = data["firstName"] as? String, 
      let carData = data["car"] as? [String: AnyObject], 
      let car = Car(JSONData: carData) 
     else {return nil} 
+0

爲什麼'guard'我不能使用'as!',但必須使用'as?' –

+0

這是因爲'guard'檢查給定的變量是否可選。 'as!'表示變量**將是一個隱含的解包可選**,所以這種「跳過問題」的「保護」要求。 – the4kman

0

,你可以嘗試像

struct Person { 
    let firstName: String 
    let car: Car 

    init?(JSONData data:[String: AnyObject]) { 
     guard let firstName = data["firstName"] as? String, 
      let carJSON = data["car"] as? [String: AnyObject?], 
      let car = Car(data: carJSON) 
      else {return nil} 
     self.firstName = firstName 
     self.car = car 
    } 

} 

汽車

struct Car { 
    let year: Int 
    let brand: String 

    init?(data: [String: AnyObject?]) { 
     guard let brand = data["brand"] as? String, 
      let year = data["year"] as? Int 
      else {return nil} 
     self.brand = brand 
     self.year = year 
    } 
} 
+0

在'Person'的'guard'中,我應該使用'as?汽車'或'as! Car'?爲什麼不是另一個? –

+0

@ Leem.fin'guard'必須在條件中需要一個可選類型,所以應該使用'as?'而不是''!'。 – Akhilrajtr

0

改變汽車結構與此代碼 -

struct Car { 
    let year: Int 
    let brand: String 

    init?(JSONData data:[String: AnyObject]) { 
     guard let brand = data["brand"] as! String, 
      let year = data["year"] as! Int 
     else {return nil} 
     self.brand = brand 
     self.year = year 
    } 
} 

並改變結構的人本 -

struct Person { 
    let firstName: String 
    let car: Car 

    init?(JSONData data:[String: AnyObject]) { 
     guard let firstName = data["firstName"] as! String, 
      let car = Car(JSONData:data["car"]) 
     else {return nil} 
     self.firstName = firstName 
     self.car = car 
    } 

} 
0
作爲

夫特4+介紹Codable用於編碼&與外部表示進行解碼(JSON,plist中)

JsonData -

let jsonExample = """ 
{ 
    "firstName": "John", 
     "car": { 
      "year": 2009, 
      "brand": "BMW" 
     } 

} 
""".data(using: .utf8)! 

結構與可編碼協議 -

struct UserData: Codable{ 
     var firstName: String 
     var car: CarData 
    } 
    struct CarData: Codable{ 
     var year: Int 
     var brand: String 
     init(from decoder: Decoder) throws { 
      let values = try decoder.container(keyedBy: CodingKeys.self) 
      year = try values.decode(Int.self, forKey: .year) 
      brand = try values.decode(String.self, forKey: .brand) 
     } 
    } 

用途區內─

let jsonDecoder = JSONDecoder() 
     do { 
      let modelResult = try jsonDecoder.decode(UserData.self,from: jsonExample) 
      print("firstName is \(modelResult.firstName)")//prints John 
      print("car brand is \(modelResult.car.brand)")//Prints BMW 

     } catch { 
      print(error) 
     } 

如果的JSON是與各自的結構的不同勢鍵然後用CodingKeys

例 -

let jsonExample = """ 
{ 
    "firstNameOfBuyer": "John", 
     "car": { 
      "year-of-made": 2009, 
      "brand-name": "BMW" 
     } 

} 
""".data(using: .utf8)! 
    struct UserData: Codable { 
     var firstName: String 
     var car: CarData 
     private enum CodingKeys: String, CodingKey { 
      case firstName = "firstNameOfBuyer" 
      case car 
     } 

    } 
    struct CarData: Codable{ 
     var year: Int 
     var brand: String 
     private enum CodingKeys: String, CodingKey { 
      case year = "year-of-made" 
      case brand = "brand-name" 

     } 
     init(from decoder: Decoder) throws { 
      let values = try decoder.container(keyedBy: CodingKeys.self) 
      year = try values.decode(Int.self, forKey: .year) 
      brand = try values.decode(String.self, forKey: .brand) 
     } 
    }