快速JSONDecoder将单个对象解析为对象数组

时间:2019-10-18 15:50:09

标签: json swift codable

我有一个包含多个“ Dozzs”对象的Json文件。 在每个“ Dozzs”对象内部是一个或多个“ Dozz”对象。因此,我将“ Dozzs”对象与一个“ Dozz”对象混合在一起,将“ Dozzs”对象与一个“ Dozz”对象数组混合在一起。 但是我不能在结构Route::group(['prefix' => 'auth'], function () { Route::post('login','AuthController@login'); Route::post('signup','AuthController@signup'); Route::group(['middleware' => 'auth:api'], function () { Route::get('logout','AuthController@logout'); Route::get('user','AuthController@user'); }); }); 中说,如果是这种情况,JSONDecoder不想将一个“ Dozz”解析为一个“ Dozz”数组。

是否有一种方法(如果Dozzs中只有一个Dozz对象)将其解析为数组? 因此,我始终在结构中包含一个或多个对象的Dozz-Array,并且JSONDecoder不会崩溃。

这是我当前的结构:

let doz: [Dozz]

这是json:

struct Dozzs : Codable {
 let doz : Dozz?
 //let doz: [Dozz]?
  }

帮助会很棒?

2 个答案:

答案 0 :(得分:1)

我整理了一个样本,希望对您有所帮助。


let json1 = """
{
"doz": {
        "dozProp1": "prop1",
        "dozProp2": "prop2"
    }
}
"""
let json2 = """
{

"doz": [
{
"dozProp1": "prop1",
"dozProp2": "prop2"
},
{
"dozProp1": "prop1_23",
"dozProp2": "prop2_34"
}
]
}
"""

public struct Doz: Decodable {
    var dozProp1: String
    var dozProp2: String
}

public enum JSONValue: Decodable {
    case arrayDoz([Doz])
    case doz(Doz)

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let value = try? container.decode([Doz].self) {
            self = .arrayDoz(value)
        } else  if let value = try? container.decode(Doz.self) {
            self = .doz(value)
        } else {
            throw DecodingError.typeMismatch(JSONValue.self, DecodingError.Context(codingPath: container.codingPath, debugDescription: "Not doz"))
        }
    }
}


public struct DecodingDoz: Decodable {
    var doz: JSONValue
}

let parsed1: DecodingDoz = try JSONDecoder().decode(DecodingDoz.self, from: json1.data(using: .utf8)!)
let parsed2: DecodingDoz = try JSONDecoder().decode(DecodingDoz.self, from: json2.data(using: .utf8)!)

print(parsed1.doz)
print(parsed2.doz)

一个简短的解释,所以我用Doz的两个可能值创建了一个枚举,并做了一个是否让json解析出Doz类型的检查,我发现匹配项是否则,将引发异常。

快乐编码

答案 1 :(得分:0)

您应该覆盖解码器中的init并解码JSON。在下面的代码中,我首先尝试解码单个Doz对象,如果结果为nil,然后尝试解码Doz数组。

struct Dozzs : Decodable {
    let doz : [Dozz]?

    // Coding Keys
    enum MyDozzsKeys: String, CodingKey {
      case doz
    }

    // Overriding init
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: MyDozzsKeys.self)
        if let doz    = try? container.decode(Dozz.self, forKey: .doz) {
            self.doz  = [doz]
        } else {
            let doz   = try container.decode([Dozz].self, forKey: .doz)
            self.doz  = doz
        }
    }

 }

更新: 根据您的JSON,模型应该是这样的:

struct Dozzs : Decodable {
    let dozzs : [Doz]?

    enum MyDozzsKeys: String, CodingKey {
      case dozzs
    }

    init(from decoder: Decoder) throws {
      let container = try decoder.container(keyedBy: MyDozzsKeys.self)
        if let doz = try? container.decode(Doz.self, forKey: .dozzs) {
            self.dozzs = [doz]
        } else {
            let doz = try container.decode([Doz].self, forKey: .dozzs)
            self.dozzs = doz
        }
    }

 }

struct Doz: Decodable {
    let doz: DozData
}

struct DozData: Decodable {
    let type: String
    let key: String
    enum CodingKeys: String, CodingKey {
        case type = "-type"
        case key = "-key"
    }
}

struct Test: Decodable {
    let test: [Dozzs]?
}

并像这样解码:

try JSONDecoder().decode(Test.self, from: jsonTest)