Codable对象将数组元素映射到字符串

时间:2017-11-21 17:37:04

标签: ios json swift codable decodable

我有一个(烦人的)情况,我的后端会返回一个这样的对象:

{
"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 } } 方法,我不知道如何进行这种映射。有什么想法吗?

2 个答案:

答案 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来更清楚地区分底层模型与其显示。