[英]How to directly convert a Dictionary to a Codable instance in Swift?
我的應用程序從我們的服務器接收二進制數據。 在我的舊 Objective-C 代碼中,我按如下方式處理響應數據:
現在我想用 Swift 來做這件事,我剛剛了解到 Codable 協議是多么方便。 但是,看起來這個協議實現了,我只能用Data/NSData來轉換它,這使得上面的過程變成了這樣:
所以我的問題是, Codable 對象可以直接從字典派生嗎?
編輯:
謝謝你們的回答,但讓我澄清一下。 雖然響應JSON格式有些固定,但是請求和響應有很多不同,所以信息部分是不同的。 例如:
因此, Codable類/結構應該僅從信息部分構建,而不是從整個響應數據構建,這就是為什么我不能簡單地應用第 2 步和第 4 步來實現這一點。
看起來您的 JSON 如下所示:
let r1 = Data("""
{"code": "0", "info": {"user_id": 123456}}
""".utf8)
let r2 = Data("""
{"code": "0", "info": {"temperature": 20, "country": "London"}}
""".utf8)
和“信息”類型看起來像這樣:
struct UserID: Codable {
var userId: Int
}
struct WeatherTemperature: Codable {
var temperature: Int
var country: String
}
我假設有一個解碼器可以進行蛇形大小寫轉換(您可以通過實現 CodingKeys 或其他方式來替換它):
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
鑒於此,您需要一個通用的 Response 類型:
struct Response<Info: Codable>: Codable {
var code: String
var info: Info
}
有了它,您可以直接從 JSON 對象解碼您的響應:
let userID = try decoder.decode(Response<UserID>.self, from: r1).info
let weather = try decoder.decode(Response<WeatherTemperature>.self, from: r2).info
將 json 字符串轉換為數據,然后使用 json 解碼器轉換為可編碼結構
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}]}"
let data = json.data(using: .utf8)
let decoder = JSONDecoder()
if let data = data, let model = try? decoder.decode(YourCodableModel.self, from: data) {
print(model)
}
不,不是直接的,是的,有點。 使困惑? 我來解釋一下。
Codable
旨在對Data
進行編碼/解碼,JSON 是當今最流行的編碼,但您也可以使用 plist 或編寫自己的自定義編碼器/解碼器。
但是堅持使用標准編碼器,如果您想從Dictionary
轉換為符合Codable
的類型,您可以通過將Dictionary
編碼為 JSON(或 plist)然后將生成的Data
解碼為Codable
東西...基本上是你描述的過程。 請注意,如果Dictionary
的鍵和值類型都是Codable
(例如[String: Int]
),您可以使用 JSONEncoder/Decoder 而不是JSONSerialization
。 但是,例如,如果是[String: Any]
,則您需要使用JSONSerialization
,因為Any
不符合Codable
。
話雖如此,您可以擴展Codable
以包含一個帶有Dictionary
的可失敗或拋出初始值設定項,您可以在其中將Dictionary
編碼為Data
,然后使用JSONDecoder
進行解碼。 這仍然是您已經在做的過程,只是任何Codable
都會自動使其易於使用。
extension Codable
{
init<Key: Hashable, Value>(_ dict: [Key: Value]) throws where Key: Codable, Value: Codable
{
let data = try JSONEncoder().encode(dict)
self = try JSONDecoder().decode(Self.self, from: data)
}
}
但這聽起來並不像您實際上需要任何可編碼的東西來從Dictionary
初始化,而只是您的模型。 在這種情況下,與其擴展Codable
,不如擴展您的模型。
{
"code": "0",
"info": {
"user_id": 123456
}
}
因此,如上所述,只要您的結構匹配,您就可以一步完成此操作。
例如:
struct ServerResponse: Codable {
var code: Int
var info: [String:Int]
}
或者:
struct ServerResponse: Codable {
var code: Int
var info: Info
}
struct Info: Codable {
var user_id: Int
}
然后簡單地
let serverResponse = try? JSONDecoder().decode(ServerResponse.self, from: your_server_json_data)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.