动态解码 JSON 个单个对象或对象数组
Decode JSON single object or array of object dynamically
假设我有一个来自 GET 方法的 JSON 响应数组,例如:
[{
"id":"1",
"Name":"John Doe",
},{
"id":"2",
"Name":"Jane Doe",
}]
从使用 id 参数的 POST 方法我只有 1 个对象 JSON 响应:
{
"id":"1",
"Name":"John Doe",
}
如何编写一个方法来动态解码 JSON?
目前,这就是我正在使用的:
func convertJSON<T:Decodable>(result: Any?, model: T.Type) -> T? {
if let res = result {
do {
let data = try JSONSerialization.data(withJSONObject: res, options: JSONSerialization.WritingOptions.prettyPrinted)
return try JSONDecoder().decode(model, from: data)
} catch {
print(error)
return nil
}
} else {
return nil
}
}
该方法可用于使用动态模型对单个对象进行解码,但我只是想不出它来动态处理单个对象/对象数组。
The most I can get with is just using a duplicate of the method but replacing T with
[T] in the method parameter and return type, if the response is an array.
我乐于接受任何建议,感谢您的帮助,在此先感谢您。
编辑:如果此问题与 this 重复,我不确定标记的答案如何成为解决方案。
一个解决方案可能是总是 return [Model]?
.
在您的函数中,首先尝试解码为 Model
,成功时 return 一个包含单个解码对象的数组。如果失败则尝试解码为 [Model]
,成功时 return 解码对象 else return nil.
使用您的示例 JSON,我创建了一个结构:
struct Person: Codable {
let id, name: String
enum CodingKeys: String, CodingKey {
case id
case name = "Name"
}
}
然后我创建了一个结构,其中包含一些方法,可以从 String
或可选的 Data
解码。
struct Json2Type<T: Decodable> {
// From data to type T
static public func convertJson(_ data: Data?) -> [T]? {
// Check data is not nil
guard let data = data else { return nil }
let decoder = JSONDecoder()
// First try to decode as a single object
if let singleObject = try? decoder.decode(T.self, from: data) {
// On success return the single object inside an array
return [singleObject]
}
// Try to decode as multiple objects
guard let multipleObjects = try? decoder.decode([T].self, from: data) else { return nil }
return multipleObjects
}
// Another function to decode from String
static public func convertJson(_ string: String) -> [T]? {
return convertJson(string.data(using: .utf8))
}
}
最后调用你喜欢的方法:
Json2Type<Person>.convertJson(JsonAsDataOrString)
更新:@odin_123,一种将Model
或[Model]
作为return值的方法可以是使用 enum
完成。我们甚至可以在那里添加错误条件以避免 returning 选项。让我们将枚举定义为:
enum SingleMulipleResult<T> {
case single(T)
case multiple([T])
case error
}
然后结构变成这样:
struct Json2Type<T: Decodable> {
static public func convertJson(_ data: Data?) -> SingleMulipleResult<T> {
guard let data = data else { return .error }
let decoder = JSONDecoder()
if let singleObject = try? decoder.decode(T.self, from: data) {
return .single(singleObject)
}
guard let multipleObjects = try? decoder.decode([T].self, from: data) else { return .error }
return .multiple(multipleObjects)
}
static public func convertJson(_ string: String) -> SingleMulipleResult<T> {
return convertJson(string.data(using: .utf8))
}
}
你可以像我们之前一样调用它:
let response = Json2Type<Person>.convertJson(JsonAsDataOrString)
并使用开关检查每个可能的响应值:
switch(response) {
case .single(let object):
print("One value: \(object)")
case .multiple(let objects):
print("Multiple values: \(objects)")
case .error:
print("Error!!!!")
}
假设我有一个来自 GET 方法的 JSON 响应数组,例如:
[{
"id":"1",
"Name":"John Doe",
},{
"id":"2",
"Name":"Jane Doe",
}]
从使用 id 参数的 POST 方法我只有 1 个对象 JSON 响应:
{
"id":"1",
"Name":"John Doe",
}
如何编写一个方法来动态解码 JSON? 目前,这就是我正在使用的:
func convertJSON<T:Decodable>(result: Any?, model: T.Type) -> T? {
if let res = result {
do {
let data = try JSONSerialization.data(withJSONObject: res, options: JSONSerialization.WritingOptions.prettyPrinted)
return try JSONDecoder().decode(model, from: data)
} catch {
print(error)
return nil
}
} else {
return nil
}
}
该方法可用于使用动态模型对单个对象进行解码,但我只是想不出它来动态处理单个对象/对象数组。
The most I can get with is just using a duplicate of the method but replacing T with [T] in the method parameter and return type, if the response is an array.
我乐于接受任何建议,感谢您的帮助,在此先感谢您。
编辑:如果此问题与 this 重复,我不确定标记的答案如何成为解决方案。
一个解决方案可能是总是 return [Model]?
.
在您的函数中,首先尝试解码为 Model
,成功时 return 一个包含单个解码对象的数组。如果失败则尝试解码为 [Model]
,成功时 return 解码对象 else return nil.
使用您的示例 JSON,我创建了一个结构:
struct Person: Codable {
let id, name: String
enum CodingKeys: String, CodingKey {
case id
case name = "Name"
}
}
然后我创建了一个结构,其中包含一些方法,可以从 String
或可选的 Data
解码。
struct Json2Type<T: Decodable> {
// From data to type T
static public func convertJson(_ data: Data?) -> [T]? {
// Check data is not nil
guard let data = data else { return nil }
let decoder = JSONDecoder()
// First try to decode as a single object
if let singleObject = try? decoder.decode(T.self, from: data) {
// On success return the single object inside an array
return [singleObject]
}
// Try to decode as multiple objects
guard let multipleObjects = try? decoder.decode([T].self, from: data) else { return nil }
return multipleObjects
}
// Another function to decode from String
static public func convertJson(_ string: String) -> [T]? {
return convertJson(string.data(using: .utf8))
}
}
最后调用你喜欢的方法:
Json2Type<Person>.convertJson(JsonAsDataOrString)
更新:@odin_123,一种将Model
或[Model]
作为return值的方法可以是使用 enum
完成。我们甚至可以在那里添加错误条件以避免 returning 选项。让我们将枚举定义为:
enum SingleMulipleResult<T> {
case single(T)
case multiple([T])
case error
}
然后结构变成这样:
struct Json2Type<T: Decodable> {
static public func convertJson(_ data: Data?) -> SingleMulipleResult<T> {
guard let data = data else { return .error }
let decoder = JSONDecoder()
if let singleObject = try? decoder.decode(T.self, from: data) {
return .single(singleObject)
}
guard let multipleObjects = try? decoder.decode([T].self, from: data) else { return .error }
return .multiple(multipleObjects)
}
static public func convertJson(_ string: String) -> SingleMulipleResult<T> {
return convertJson(string.data(using: .utf8))
}
}
你可以像我们之前一样调用它:
let response = Json2Type<Person>.convertJson(JsonAsDataOrString)
并使用开关检查每个可能的响应值:
switch(response) {
case .single(let object):
print("One value: \(object)")
case .multiple(let objects):
print("Multiple values: \(objects)")
case .error:
print("Error!!!!")
}