如何使用自定义类型属性从 JSON 初始化模型类
Posted
技术标签:
【中文标题】如何使用自定义类型属性从 JSON 初始化模型类【英文标题】:How to initialize model class from JSON with custom type attribute 【发布时间】:2017-08-04 12:02:21 【问题描述】:我知道我可以为我的模型类创建可失败的初始化程序,以通过以下方式从 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
使上述可失败初始化程序与自定义类型 Car
一起用于 JSON 数据解析的正确方法是什么?
例如JSON:
“firstName”: “John”,
“car”:
“year”: 2009,
“brand”: “BMW”
【问题讨论】:
【参考方案1】:首先,您在guard
语句中没有返回可选参数。在其中将!
更改为?
。
其次,您应该将数据传递给初始化程序并检查它是否为 nil。
guard let firstName = data["firstName"] as? String,
let carData = data["car"] as? [String: AnyObject],
let car = Car(JSONData: carData)
else return nil
【讨论】:
为什么在guard
我不能用as!
却必须用as?
这是因为guard
检查给定变量是否是可选的。 as!
表示变量将是一个隐式展开的可选,所以guard
提出的那种“跳过问题”。【参考方案2】:
使用此代码更改 Car 结构-
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
并将 Person 结构更改为 this-
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
【讨论】:
【参考方案3】:你可以试试
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
【讨论】:
在guard
的Person
中,我应该使用as? Car
还是as! Car
? & 为什么不是另一个?
@Leem.fin guard
必须在条件中使用可选类型,因此应使用as?
而不是as!
。【参考方案4】:
随着 Swift 4+ 引入 Codable 用于使用外部表示(JSON,Plist)进行编码和解码
JsonData -
let jsonExample = """
"firstName": "John",
"car":
"year": 2009,
"brand": "BMW"
""".data(using: .utf8)!
采用 Codable 协议的结构-
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)
【讨论】:
以上是关于如何使用自定义类型属性从 JSON 初始化模型类的主要内容,如果未能解决你的问题,请参考以下文章