我有一个(烦人的)情况,我的后端会返回一个这样的对象:
{
"user": {
"name": [
"John"
],
"familyName": [
"Johnson"
]
}
}
其中每个属性都是一个以字符串作为第一个元素的数组。在我的数据模型struct
中,我可以将每个属性声明为数组,但这确实很难看。我希望我的模型如此:
struct User: Codable {
var user: String
var familyName: String
}
但是这当然会因编码/解码而失败,因为类型不匹配。到目前为止,我已经使用ObjectMapper
库提供了Map
对象和currentValue
属性,我可以将我的属性声明为String
类型,并在我的模型中{{1方法通过这个函数赋值:
init
但是现在我正在转换为extension Map {
public func firstFromArray<T>(key: String) -> T? {
if let array = self[key].currentValue as? [T] {
return array.first
}
return self[key].currentValue as? T
}
}
方法,我不知道如何进行这种映射。有什么想法吗?
答案 0 :(得分:1)
您可以覆盖init(from decoder: Decoder)
:
let json = """
{
"user": {
"name": [
"John"
],
"familyName": [
"Johnson"
]
}
}
"""
struct User: Codable {
var name: String
var familyName: String
init(from decoder: Decoder) throws {
let container:KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self)
let nameArray = try container.decode([String].self, forKey: .name)
let familyNameArray = try container.decode([String].self, forKey: .familyName)
self.name = nameArray.first!
self.familyName = familyNameArray.first!
}
enum CodingKeys: String, CodingKey {
case name
case familyName
}
}
let data = json.data(using: .utf8)!
let decodedDictionary = try JSONDecoder().decode(Dictionary<String, User>.self, from: data)
print(decodedDictionary) // ["user": __lldb_expr_48.User(name: "John", familyName: "Johnson")]
let encodedData = try JSONEncoder().encode(decodedDictionary["user"]!)
let encodedStr = String(data: encodedData, encoding: .utf8)
print(encodedStr!) // {"name":"John","familyName":"Johnson"}
答案 1 :(得分:1)
我倾向于使您的模型适应进入的数据并创建用于应用程序的计算属性,例如
struct User: Codable {
var user: [String]
var familyName: [String]
var userFirstName: String? {
return user.first
}
var userFamilyName: String? {
return familyName.first
}
}
这使您可以轻松地保持与进入的数据结构的模仿,而无需覆盖编码/解码的维护成本。
如果它适合您的设计,您还可以使用UI包装器Type或ViewModel来更清楚地区分底层模型与其显示。