如何在SWIFT中将字典直接转换为可编码的示例?

sauutmhj  于 2022-10-23  发布在  Swift
关注(0)|答案(4)|浏览(489)

我的应用程序从我们的服务器接收二进制数据。在我的旧的Objective-C代码中,我按如下方式处理响应数据:
1.使用NSJSON序列化将NSData转换为NSDictionary,包含如下数据:{“code”:“0”,“Info”:{“user_id”:123456}},
1.编写MTLModel子类
1.使用Mantle接口将上面的INFO字典{“user_id”:123456}转换成我的模型
现在我想用SWIFT来做这件事,我刚刚了解到可编码协议是多么的方便。但是,看起来实现了这个协议,我只能用Data/NSData进行转换,这使得上面的程序变成了这样:
1.同上
1.编写符合可编码协议的结构/类
1.使用NSJSON序列化将INFO字典{“user_id”:123456}重新编码为data/NSData
1.使用JSONDecoder将这些数据解码到我的模型中
所以我的问题是,一个可编码的对象可以直接从词典中派生出来吗?

编辑:

谢谢你们的回答,但让我稍微澄清一下。虽然响应JSON格式有些固定,但是有很多不同的请求和响应,所以INFO部分是不同的。例如:

  • r1:{“CODE”:“0”,“INFO”:{“USER_ID”:123456}}是用户id请求的响应
  • r2:{“code”:“0”,“Info”:{“Temperature”:20,“Country”:“London”}}是天气温度请求的响应

因此,可编码的类/结构应该只从信息部分构造,而不是从整个响应数据构造,这就是为什么我不能简单地应用步骤2和4来完成这一点。

kxxlusnw

kxxlusnw1#

看起来您的JSON如下所示:

  1. let r1 = Data("""
  2. {"code": "0", "info": {"user_id": 123456}}
  3. """.utf8)
  4. let r2 = Data("""
  5. {"code": "0", "info": {"temperature": 20, "country": "London"}}
  6. """.utf8)

和如下所示的“信息”类型:

  1. struct UserID: Codable {
  2. var userId: Int
  3. }
  4. struct WeatherTemperature: Codable {
  5. var temperature: Int
  6. var country: String
  7. }

我假设有一个解码器来执行SnakeCase转换(您可以通过实现CodingKeys或其他任何方式来替换它):

  1. let decoder = JSONDecoder()
  2. decoder.keyDecodingStrategy = .convertFromSnakeCase

鉴于此,您需要一个泛型响应类型:

  1. struct Response<Info: Codable>: Codable {
  2. var code: String
  3. var info: Info
  4. }

这样,您就可以直接从JSON对象解码响应:

  1. let userID = try decoder.decode(Response<UserID>.self, from: r1).info
  2. let weather = try decoder.decode(Response<WeatherTemperature>.self, from: r2).info
展开查看全部
k5hmc34c

k5hmc34c2#

使用JSON解码器将JSON字符串转换为数据,然后转换为可编码的结构

  1. let json = "{\"CustomerTypeID\":3,\"CustomerID\":4330,\"CustomerName\":\"Black :)\",\"CustomerTypeName\":\"Member\",\"IsWalkedInCustomer\":false,\"Email\":\"black@yopmail.com\",\"Mobile\":\"+447400369852\",\"AllowPartPaymentOnCore\":true,\"ServiceBookingList\":[{\"SaleStatusTypeID\":2,\"SaleStatusTypeName\":\"Paid\",\"ServiceName\":\"Nail Polish Service\",\"BookingStatusTypeID\":1,\"BookingStatusTypeName\":\"Booked\",\"SaleID\":71861,\"ID\":83756,\"ServiceCategoryID\":85,\"ServiceID\":173,\"ServicePackageID\":245,\"Price\":0.00,\"TotalPrice\":0.00,\"CleaningTimeInMinute\":10,\"StartDate\":\"2021-06-30T00:00:00Z\",\"StartTime\":\"11:00:00\",\"EndTime\":\"11:30:00\",\"AssignedToStaffID\":268,\"FacilityID\":0,\"Description\":\"\",\"IsPartialPaid\":false,\"TotalAmountPaid\":0.0,\"SaleRefundAmount\":0.00,\"AssignedToStaffName\":\"Iqra Rasheed\",\"CustomerMembershipID\":null,\"Duration\":\"00:30\",\"LastUpdatedByName\":\"Iqra Rasheed\",\"FacilityName\":\"\",\"StaffImagePath\":\"Staff_fabf1c3a-e2bf-45c6-b7f1-3cddd17fb358.jpg\",\"TotalTaxPercentage\":22.00,\"TotalDiscountAmount\":0.00,\"IsFree\":false,\"HasUnSubmittedForm\":true,\"HasAtleastOneMandatoryForm\":true}]}"
  2. let data = json.data(using: .utf8)
  3. let decoder = JSONDecoder()
  4. if let data = data, let model = try? decoder.decode(YourCodableModel.self, from: data) {
  5. print(model)
  6. }
knpiaxh1

knpiaxh13#

不,不是直接的,是的,有点。困惑?我会解释的。
Codable用于对Data进行编码/解码,其中JSON是目前最流行的编码方式,但您也可以使用PLIST或编写您自己的编解码器。
但是坚持使用标准编码器,如果您希望从Dictionary转换为符合Decodable的类型(包括符合Codable的任何内容),您可以通过将Dictionary编码为JSON(或plist),然后将生成的Data解码为Decodable来实现。这基本上就是你所描述的过程。注意,如果Dictionary的键和值类型都是Codable(例如[String: Int]),则可以使用JSONEncoder/Decoder而不是JSONSerialization。但是,如果它是例如[String: Any],则需要使用JSONSerialization,因为Any不符合Codable
这样说来,您可以扩展Decodable以包括一个接受Dictionary的失败或抛出的初始值设定项,在该初始值设定项中,您将字典编码为Data,然后使用JSONDecoder进行解码。它仍然是您已经在执行的过程,只是Decodable的任何内容都将自动使其可用,以便于使用。

  1. extension Decodable
  2. {
  3. init<Key: Hashable, Value>(_ dict: [Key: Value]) throws where Key: Codable, Value: Codable
  4. {
  5. let data = try JSONEncoder().encode(dict)
  6. self = try JSONDecoder().decode(Self.self, from: data)
  7. }
  8. }

但听起来你实际上并不需要任何可编码的东西才能从Dictionary初始化,只需要你的型号。在这种情况下,与其扩展Decodable,不如扩展您的模型。
如果词典中有Any或其他非Codable值,则可以对JSONSerialization执行类似的操作:

  1. extension Decodable
  2. {
  3. init<Key: Hashable>(_ dict: [Key: Any]) throws
  4. {
  5. let data = try JSONSerialization.data(withJSONObject: dict, options: [])
  6. self = try JSONDecoder().decode(Self.self, from: data)
  7. }
  8. }

要使用它:

  1. struct MyModel: Codable {...}
  2. let dict: [String: Any] = getDictionarySomehow()
  3. let myModel = try MyModel(dict)
展开查看全部
gzszwxb4

gzszwxb44#

  1. {
  2. "code": "0",
  3. "info": {
  4. "user_id": 123456
  5. }
  6. }

因此,正如上面所讨论的,只要您的结构匹配,您就可以在一个步骤中完成此操作。
例如:

  1. struct ServerResponse: Codable {
  2. var code: Int
  3. var info: [String:Int]
  4. }

或者:

  1. struct ServerResponse: Codable {
  2. var code: Int
  3. var info: Info
  4. }
  5. struct Info: Codable {
  6. var user_id: Int
  7. }

然后简单地

  1. let serverResponse = try? JSONDecoder().decode(ServerResponse.self, from: your_server_json_data)
展开查看全部

相关问题