假设我的Customer数据类型包含一个metadata属性,该属性可以包含客户对象中的任何JSON字典
struct Customer {
let id: String
let email: String
let metadata: [String: Any]
}
Run Code Online (Sandbox Code Playgroud)
{
"object": "customer",
"id": "4yq6txdpfadhbaqnwp3",
"email": "john.doe@example.com",
"metadata": {
"link_id": "linked-id",
"buy_count": 4
}
}
Run Code Online (Sandbox Code Playgroud)
该metadata属性可以是任意JSON映射对象.
在我NSJSONDeserialization使用新的Swift 4 Decodable协议从反序列化的JSON中转换属性之前,我仍然无法想到这样做的方法.
有人知道如何使用可解码协议在Swift 4中实现这一目标吗?
我正在使用Swift 4并尝试解析一些JSON数据,这些数据显然在某些情况下可以为同一个键具有不同的类型值,例如:
{
"type": 0.0
}
Run Code Online (Sandbox Code Playgroud)
和
{
"type": "12.44591406"
}
Run Code Online (Sandbox Code Playgroud)
我实际上坚持定义我,struct因为我无法弄清楚如何处理这种情况,因为
struct ItemRaw: Codable {
let parentType: String
enum CodingKeys: String, CodingKey {
case parentType = "type"
}
}
Run Code Online (Sandbox Code Playgroud)
投掷"Expected to decode String but found a number instead.",当然,
struct ItemRaw: Codable {
let parentType: Float
enum CodingKeys: String, CodingKey {
case parentType = "type"
}
}
Run Code Online (Sandbox Code Playgroud)
因此投掷"Expected to decode Float but found a string/data instead.".
在定义我的时候如何处理这个(和类似的)情况struct呢?
TL; DR
有没有一种方法可以使用JSONDecoder并编写一个函数,它只是从给定的json读出指定的可解码类型的字段值?
成像我有以下json:
{
"product":{
"name":"PR1",
"price":20
},
"employee":{
"lastName":"Smith",
"department":"IT",
"manager":"Anderson"
}
}
Run Code Online (Sandbox Code Playgroud)
我有2个Decodable结构:
struct Product: Decodable {
var name: String
var price: Int
}
struct Employee: Decodable {
var lastName: String
var department: String
var manager: String
}
Run Code Online (Sandbox Code Playgroud)
我想写一个函数
func getValue<T:Decodable>(from json: Data, field: String) -> T { ... }
Run Code Online (Sandbox Code Playgroud)
所以我可以这样称呼它:
let product: Product = getValue(from: myJson, field: "product")
let employee: Employee = getValue(from: myJson, field: "employee")
Run Code Online (Sandbox Code Playgroud)
这是可能的,JSONDecoder或者我应该弄乱JSONSerialization,首先读出给定json的"子树",然后将其传递给解码器?在swift中似乎不允许在泛型函数中定义结构.
使用Swift 3 JSONSerialization,如果您的数据模型的一部分是完全动态的,您可以随时保留反序列化数据,Any并让消费者处理它.
有了Swift 4 Codable,我想这样做:
struct Foo : Codable {
let bar: Any;
}
Run Code Online (Sandbox Code Playgroud)
但我明白了
JSONPlayground.playground:4:9: note: cannot automatically synthesize 'Decodable' because 'Any' does not conform to 'Decodable'
let bar: Any;
^
Run Code Online (Sandbox Code Playgroud)
如果我能够实现自己的那个,那就不会是世界末日Decodable,但这需要Decoder支持解码Any,据我所知,它不会.例如:
extension Foo {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let result = try container.decode(AnyClass.self)
}
}
Run Code Online (Sandbox Code Playgroud)
给
error: JSONPlayground.playground:4:36: error: cannot invoke 'decode' with an argument list of type '(AnyClass.Protocol)'
let result …Run Code Online (Sandbox Code Playgroud) {
"values":[
[1,1,7,"Azuan Child","Anak Azuan","12345","ACTIVE","Morning",7,12,"2017-11-09 19:45:00"],
[28,1,0,"Azuan Child2","Amran","123456","ACTIVE","Evening",1,29,"2017-11-09 19:45:00"]
]
}
Run Code Online (Sandbox Code Playgroud)
好的,这是我从服务器收到的 json 格式
现在我想将它解码到我的结构中,但仍然没有运气。
struct ChildrenTable: Decodable {
var values: [[String]]?
}
Run Code Online (Sandbox Code Playgroud)
我在 URLSession 上的调用者方法看起来像这样
URLSession.shared.dataTask(with: request) { (data, response, err) in
guard let data = data else { return }
let dataAsString = String(data: data, encoding: .utf8)
print(dataAsString)
do {
let children = try
JSONDecoder().decode(ChildrenTable.self, from: data)
print (children)
} catch let jsonErr {
print ("Error serializing json: ", jsonErr)
}
}.resume()
Run Code Online (Sandbox Code Playgroud)
我得到的错误是
Error serializing json:
typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: …Run Code Online (Sandbox Code Playgroud) 我正在从 API 检索 JSON,并且想为我使用的每个端点创建一个模型。
\n\n所有端点都使用以下格式:
\n\n{\n "id": "xxxxxx",\n "result": {\xe2\x80\xa6},\n "error": null\n}\nRun Code Online (Sandbox Code Playgroud)\n\n关键是:
\n\nid始终是一个字符串error可以为空或包含键的对象result可以为null;一个对象或一个数组。我遇到的问题是,在端点之一上,结果是数组的数组:
\n\n{\n "id": "xxxxxx",\n "result": [\n [\n "client_id",\n "name",\n 50,\n "status"\n ]\n ],\n "error": null\n}\nRun Code Online (Sandbox Code Playgroud)\n\n正如您所看到的,我有数组的数组,其中值可以是字符串或整数。
\n\n如何使用 Decodable 协议对其进行解码,然后根据其原始值将这些解码值用作 String 或 Int ?
\n寻找一些关于如何处理我最近遇到的场景的输入.
我一直在使用Swift 4s Codable成功,但今天发现了一个我没想到的崩溃.我正在使用的API表示它返回了一个boolean密钥manage_stock.
我的存根结构看起来像:
struct Product: Codable {
var manage_stock: Bool?
}
Run Code Online (Sandbox Code Playgroud)
这很好用,问题是API 有时会返回string而不是a boolean.
因此,我的解码失败了:
Expected to decode Bool but found a string/data instead.
Run Code Online (Sandbox Code Playgroud)
字符串只有等于"parent",我希望它等于false.
我也可以更改我的结构,var manage_stock: String?如果这样可以更容易地从API中获取JSON数据.但是,当然,如果我改变了,我的错误只会改为:
Expected to decode String but found a number instead.
Run Code Online (Sandbox Code Playgroud)
是否有一种简单的方法来处理这种突变,或者我是否需要丢失所有Codable带来的自动化并实现我自己的init(decoder: Decoder).
干杯