Ios 解析动态JSON的模型

Ios 解析动态JSON的模型,ios,json,swift,parsing,Ios,Json,Swift,Parsing,我访问的端点可能返回两个不同JSON中的一个,这取决于用户是否需要回答安全问题: // possible response (payload) #1 { "token": "123lknk123kj1n13132" } // possible response (payload) #2 { "securityQuestion": "What is your mother's maiden name?" } 我的目标是创建一个模型,根据有效负载中存在的密钥对JSON进行不同的解

我访问的端点可能返回两个不同JSON中的一个,这取决于用户是否需要回答安全问题:

// possible response (payload) #1
{
    "token": "123lknk123kj1n13132"
}

// possible response (payload) #2
{
    "securityQuestion": "What is your mother's maiden name?"
}
我的目标是创建一个模型,根据有效负载中存在的密钥对JSON进行不同的解码(即
“token”
“securityQuestion”
目前,我收到一个解析错误,我不知道原因。

我的灵感来自于对上一个问题的精心设计的回答。我当前的代码是它的一个修改版本,它(理论上)符合我的需要。我希望我的代码的最终版本保留这种结构。我的代码如下:

/**
Enumerates the possible payloads received from Server

- success: Successful payload that contains the user's access token
- securityQuestion: Payload that contains the security question that the user has to answer to receive a token
*/
enum PayloadType: String, Decodable {
    case success
    case securityQuestion
}

protocol Payload: Decodable { static var payloadType: PayloadType { get } }

/// Model for successful response sent by the server.
struct SuccessfulResponse: Payload {
    static let payloadType = PayloadType.success
    let token: String
}

/// Model for response sent by the server which includes a security question
struct SecurityQuestionResponse: Payload {
    static let payloadType = PayloadType.securityQuestion
    let securityQuestion: String
}

/// Model for building a response sent by the server.
struct Response: Decodable {
    let data: Payload
    let payloadType: PayloadType

    init(from decoder: Decoder) throws {
        // NOTE*: This part is a little shaky, maybe this is where I am going wrong
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.payloadType = try values.decode(PayloadType.self, forKey: .payloadType)

        // payloadType will determine how the JSON is decoded
        switch self.payloadType
        {

        case .success:
            self.data = try values.decode(SuccessfulResonse.self, forKey: .data)

        case .securityQuestion:
            self.data = try values.decode(SecurityQuestionResponse.self, forKey: .data)
        }
    }

    private enum CodingKeys: String, CodingKey {
        case data
        case payloadType
    }
}

在发布这个问题之前,我查看了各种类似的帖子(,),但没有一篇真正符合需要。

我想建议一种不同的方法,不是更简单,而是更易于使用,至少对我来说更清楚

struct Token: Codable { 
   let token: String?
}

struct SecurityQuestion:Codable {
    let securityQuestion: String?
}
在请求函数中添加以下内容

URLSession.shared.dataTask(with: url, completionHandler: {data,response,error in

    do {
        let responseObject = try JSONDecoder().decode(Token.self, from: data!)

        let token = responseObject.token
        print(token)
    } catch let parseError {
        print(parseError)
        do{
            let responseObject = try JSONDecoder().decode(SecurityQuestion.self, from: data!)
            let securityQuestion = responseObject.securityQuestion
            print(securityQuestion)
        }catch{
            print(error)
        }
    }
})

主要思想是使用catch块尝试另一种解码类型,因为第一种解码类型失败,如果您有许多不同的响应,您可以使用更多catch块来执行新的解码类型,

我想建议一种不同的方法,不是更简单,而是更易于使用,至少对我来说更清楚

struct Token: Codable { 
   let token: String?
}

struct SecurityQuestion:Codable {
    let securityQuestion: String?
}
在请求函数中添加以下内容

URLSession.shared.dataTask(with: url, completionHandler: {data,response,error in

    do {
        let responseObject = try JSONDecoder().decode(Token.self, from: data!)

        let token = responseObject.token
        print(token)
    } catch let parseError {
        print(parseError)
        do{
            let responseObject = try JSONDecoder().decode(SecurityQuestion.self, from: data!)
            let securityQuestion = responseObject.securityQuestion
            print(securityQuestion)
        }catch{
            print(error)
        }
    }
})

其主要思想是使用catch块尝试另一种解码类型,因为第一种解码类型失败,如果您有许多不同的响应,您可以使用更多catch块来执行新的解码类型,

不要认为这对
Codable
来说是最好的,您需要使用SwiftyJSON/JSONSerialization 1键不值得这么头痛您是对的,仅仅用一把钥匙是不值得的。这种架构背后的基本原理是,服务器实际上可以发送多个响应,每个响应都有许多密钥。为了简洁起见,我决定不在这篇文章中列出它们,也为了避免访问者被太多的代码压垮。如果可能的话,我希望避免使用外部库。另外,我对JSONSerialization不太熟悉,这可能需要我更改此模型的体系结构。你能帮我假设这个结构保持不变吗?
struct Root:Codable{let token,securityQuestion:String?}
这是我尝试的第一件事。将
securityQuestion
/
token
设置为可选将不起作用。不确定why@DataDaddy如果您拥有有效的
JSON
数据,请从此URL尝试。不要认为这是
Codable
的最佳选择。您需要使用快速JSON/JSONSerialization 1键不值得这么头痛。您是对的,仅使用1键是不值得的。这种架构背后的基本原理是,服务器实际上可以发送多个响应,每个响应都有许多密钥。为了简洁起见,我决定不在这篇文章中列出它们,也为了避免访问者被太多的代码压垮。如果可能的话,我希望避免使用外部库。另外,我对JSONSerialization不太熟悉,这可能需要我更改此模型的体系结构。你能帮我假设这个结构保持不变吗?
struct Root:Codable{let token,securityQuestion:String?}
这是我尝试的第一件事。将
securityQuestion
/
token
设置为可选将不起作用。不确定why@DataDaddy如果您有有效的
JSON
数据,请从此URL尝试,这是一个可行的解决方案。在这里,我将保持开放的心态,并将其标记为公认的答案,尽管我注意到的一件事是,如果有多个键(为了简洁起见,我没有在帖子中包含),那么do catch语句的嵌套将很快变得丑陋,这是真的,但对于键,它将位于
init(from:Decode)中
func我有一个模型,其中解码的func比结构定义大,因为端点可以为相同的值返回字符串、doblue、int或bool,所以如果进行痛苦的解码,这是一个可行的解决方案。在这里,我将保持开放的心态,并将其标记为公认的答案,尽管我注意到的一件事是,如果有多个键(为了简洁起见,我没有在帖子中包含),那么do catch语句的嵌套将很快变得丑陋,这是真的,但对于键,它将位于
init(from:Decode)中
func我有一个模型,其中解码的func比结构定义大,因为端点可以为相同的值返回字符串、doblue、int或bool,所以如果一个完整的解码