使用可编码从JSON中提取数据有困难

使用可编码从JSON中提取数据有困难,json,swift,xcode,serialization,decoding,Json,Swift,Xcode,Serialization,Decoding,我试图从下面的JSON中提取“数据”: { "result": "success", "code": 200, "version": "1", "time": 1, "id": "NODATA", "data": { "user_address_town": { "label": "town", "required": true, "type": "string", "value": "" }, "u

我试图从下面的JSON中提取
“数据”

{
  "result": "success",
  "code": 200,
  "version": "1",
  "time": 1,
  "id": "NODATA",
  "data": {
    "user_address_town": {
      "label": "town",
      "required": true,
      "type": "string",
      "value": ""
    },
    "user_address_county": {
      "label": "county",
      "required": true,
      "type": "string"
    },
    "user_address_line_1": {
      "label": "address 1",
      "required": true,
      "type": "string",
      "value": ""
    },
    "user_address_line_2": {
      "label": "address 2",
      "required": false,
      "type": "string",
      "value": ""
    },
    "user_address_line_3": {
      "label": "address 3",
      "required": false,
      "type": "string",
      "value": ""
    },
    "user_address_postcode": {
      "label": "postcode",
      "required": false,
      "type": "string",
      "value": ""
    },
    "user_address_identifier": {
      "label": "identifier",
      "required": false,
      "type": "string",
      "value": ""
    },
    "stage": "stage1",
    "last": true,
    "ekyc": true,
    "email": {
      "label": "email address",
      "required": true,
      "type": "email",
      "value": "test+15@mailinator.com"
    },
    "password": {
      "label": "password",
      "required": true,
      "type": "string"
    },
    "user_title": {
      "label": "title",
      "required": true,
      "type": "string",
      "value": "Mrs"
    },
    "user_first_name": {
      "label": "first name",
      "required": true,
      "type": "string",
      "value": "jsns"
    },
    "user_last_name": {
      "label": "last name",
      "required": true,
      "type": "string",
      "value": "nsm"
    },
    "user_dob": {
      "label": "user date of birth",
      "type": "date",
      "required": true,
      "value": "2001-01-22"
    },
    "user_gender": {
      "label": "gender",
      "type": "string",
      "required": false,
      "value": "M"
    },
    "user_country": {
      "label": "country",
      "required": true,
      "type": "integer",
      "value": "1"
    },
    "user_telephone": {
      "label": "telephone",
      "required": false,
      "type": "string",
      "value": "946464646"
    },
    "user_name_on_card": {
      "label": "card name",
      "required": false,
      "type": "string"
    }
  }
}
我创建了一个名为
impletesignupresponse
的结构,在解码时,它应该包含
“data”
对象中的所有数据。userObject数组用于数据中较小的对象,例如
user\u address\u town

下面是我正在使用的结构:

struct IncompleteSignupResponse {
    let stage: String
    let last: Bool
    let ekyc: Bool
    let error: String?
    let userObject: [IncompleteUserObjectResponse]

}

struct IncompleteUserObjectResponse: Codable {
    let label: String
    let required: Bool
    let type: String
    let value: String
}

extension IncompleteSignupResponse: Codable {

    private enum IncompleteSignupResponseAPIResponseCodingKeys: String, CodingKey {
        case data = "data"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: IncompleteSignupResponseAPIResponseCodingKeys.self)
        let data = try container.decode(IncompleteSignupResponse.self, forKey: .data)
        stage = data.stage
        last = data.last
        ekyc = data.ekyc
        error = data.error
        userObject = data.userObject
    }
}
尝试解码结构会给出以下响应:

keyNotFound(不完全SignupResponseAppireResponseCodeKeys(stringValue:“数据”,intValue:nil),Swift.DecodingError.Context(编码路径:[不完全SignupResponseAppireResponseCodeKeys(stringValue:“数据”,intValue:nil)],debugDescription:“没有与键不完全SignupResponseAppireResponseCodeKeys(stringValue:\”数据关联的值\,intValue:nil)(“数据\”,underyingerror:nil))

我不太清楚为什么找不到关键数据,因为它没有嵌套在任何东西中

是否有我遗漏的内容?此外,我的布局是否被视为良好做法,或者是否有可以改进的地方。

使用此网站:。您可以在代码中使用此结构:

struct Welcome: Codable {
   let result: String
   let code: Int
   let version: String
   let time: Int
   let id: String
   let data: DataClass
}

struct DataClass: Codable {
     let userAddressTown, userAddressCounty, userAddressLine1, userAddressLine2: Email
     let userAddressLine3, userAddressPostcode, userAddressIdentifier: Email
     let stage: String
     let last, ekyc: Bool
     let email, password, userTitle, userFirstName: Email
     let userLastName, userDob, userGender, userCountry: Email
     let userTelephone, userNameOnCard: Email

    enum CodingKeys: String, CodingKey {
       case userAddressTown = "user_address_town"
       case userAddressCounty = "user_address_county"
       case userAddressLine1 = "user_address_line_1"
       case userAddressLine2 = "user_address_line_2"
       case userAddressLine3 = "user_address_line_3"
       case userAddressPostcode = "user_address_postcode"
       case userAddressIdentifier = "user_address_identifier"
       case stage, last, ekyc, email, password
       case userTitle = "user_title"
       case userFirstName = "user_first_name"
       case userLastName = "user_last_name"
       case userDob = "user_dob"
       case userGender = "user_gender"
       case userCountry = "user_country"
       case userTelephone = "user_telephone"
       case userNameOnCard = "user_name_on_card"
    }
}

struct Email: Codable {
   let label: String
   let emailRequired: Bool
   let type: TypeEnum
   let value: String?

   enum CodingKeys: String, CodingKey {
       case label
       case emailRequired = "required"
       case type, value
   }
}

enum TypeEnum: String, Codable {
   case date = "date"
   case email = "email"
   case integer = "integer"
   case string = "string"
}

希望这是您所期望的。mixtureType枚举可以帮助您读取这些恼人的键

添加了一个
响应
结构来包装外层

       struct IncompleteSignupResponse: CustomDebugStringConvertible{
var debugDescription: String{

    return "{stage: \(stage) ; last: \(last) ; ekyc : \(ekyc) ; error : \(String(describing: error)) ; userObject: \n \(userObject)}\n"
}
            let stage: String
            let last: Bool
            let ekyc: Bool
            let error: String?
            let userObject: [IncompleteUserObjectResponse]
        }

        enum MixtureType : Decodable{
            case Complete(IncompleteUserObjectResponse)
            case Single(Bool)
            case Simple(String)
                init(from decoder: Decoder) throws {
                            let container = try decoder.singleValueContainer()
                                do{ let temp = try container.decode(IncompleteUserObjectResponse.self); self = .Complete(temp) ; return}
                                catch{do { let temp = try container.decode(Bool.self) ; self = .Single(temp) ; return}
                                catch{ let temp = try container.decode(String.self)  ; self = .Simple(temp) ; return}}
                                try  self.init(from: decoder)
                            }

                            func getValue()-> Any{
                                switch self {
                                case let .Complete(x): return x
                                case let .Single(x): return x
                                case let .Simple(x): return x
                                }
                            }

        }

        extension IncompleteSignupResponse: Decodable {

            init(from decoder: Decoder) throws {

                do{

                    let container = try decoder.singleValueContainer()
                    let data = try container.decode([String: MixtureType].self)

                    stage = data["stage"]?.getValue() as! String
                    ekyc =  data["ekyc"]?.getValue() as! Bool
                    last = data["last"]?.getValue() as! Bool
                    error =  data["error"]?.getValue() as? String
                   userObject =    data.filter{ !(["stage" ,"ekyc"  , "last"  , "error"].contains($0.key))}.values.map{$0.getValue() as! IncompleteUserObjectResponse}

                }}

        }

     struct IncompleteUserObjectResponse: Decodable, CustomDebugStringConvertible {
var debugDescription: String {
    return "{label: \(label) ; required: \(required) ; type : \(type) ; value : \(String(describing: value))}\n"

}
            let label: String
            let required: Bool
            let type: String
            let value: String?
        }


        struct Response: Decodable {
            let   result: String
            let    code: Int
            let   version: String
            let    time: Int
            let    id:     String
            let    data: IncompleteSignupResponse

        }

        let json = """
        {
            "result": "success",
            "code": 200,
            "version": "1",
            "time": 1,
            "id": "NODATA",
           "data": {        "user_address_town": {
                    "label": "town",
                    "required": true,
                    "type": "string",
                    "value": ""
                },
                "user_address_county": {
                    "label": "county",
                    "required": true,
                    "type": "string"
                },
                "user_address_line_1": {
                    "label": "address 1",
                    "required": true,
                    "type": "string",
                    "value": ""
                },
                "user_address_line_2": {
                    "label": "address 2",
                    "required": false,
                    "type": "string",
                    "value": ""
                },
                "user_address_line_3": {
                    "label": "address 3",
                    "required": false,
                    "type": "string",
                    "value": ""
                },
                "user_address_postcode": {
                    "label": "postcode",
                    "required": false,
                    "type": "string",
                    "value": ""
                },
                "user_address_identifier": {
                    "label": "identifier",
                    "required": false,
                    "type": "string",
                    "value": ""
                },
               "stage": "stage1",
               "last": true,
               "ekyc": true,
                "email": {
                    "label": "email address",
                    "required": true,
                    "type": "email",
                    "value": "test+15@mailinator.com"
                },
                "password": {
                    "label": "password",
                    "required": true,
                    "type": "string"
                },
                "user_title": {
                    "label": "title",
                    "required": true,
                    "type": "string",
                    "value": "Mrs"
                },
                "user_first_name": {
                    "label": "first name",
                    "required": true,
                    "type": "string",
                    "value": "jsns"
                },
                "user_last_name": {
                    "label": "last name",
                    "required": true,
                    "type": "string",
                    "value": "nsm"
                },
                "user_dob": {
                    "label": "user date of birth",
                    "type": "date",
                    "required": true,
                    "value": "2001-01-22"
                },
                "user_gender": {
                    "label": "gender",
                    "type": "string",
                    "required": false,
                    "value": "M"
                },
                "user_country": {
                    "label": "country",
                    "required": true,
                    "type": "integer",
                    "value": "1"
                },
                "user_telephone": {
                    "label": "telephone",
                    "required": false,
                    "type": "string",
                    "value": "946464646"
                },
                "user_name_on_card": {
                    "label": "card name",
                    "required": false,
                    "type": "string"
                }
            }
        }


        """.data(using: .utf8)
        let obj = try JSONDecoder().decode(Response.self, from: json!)

        print(obj.data)




        {stage: stage1 ; last: true ; ekyc : true ; error : nil ; userObject:
        [{label: title ; required: true ; type : string ; value : Optional("Mrs")}
        , {label: address 2 ; required: false ; type : string ; value : Optional("")}
        , {label: telephone ; required: false ; type : string ; value : Optional("946464646")}
        , {label: password ; required: true ; type : string ; value : nil}
        , {label: country ; required: true ; type : integer ; value : Optional("1")}
        , {label: user date of birth ; required: true ; type : date ; value : Optional("2001-01-22")}
        , {label: first name ; required: true ; type : string ; value : Optional("jsns")}
        , {label: card name ; required: false ; type : string ; value : nil}
        , {label: postcode ; required: false ; type : string ; value : Optional("")}
        , {label: address 1 ; required: true ; type : string ; value : Optional("")}
        , {label: county ; required: true ; type : string ; value : nil}
        , {label: identifier ; required: false ; type : string ; value : Optional("")}
        , {label: address 3 ; required: false ; type : string ; value : Optional("")}
        , {label: gender ; required: false ; type : string ; value : Optional("M")}
        , {label: town ; required: true ; type : string ; value : Optional("")}
        , {label: email address ; required: true ; type : email ; value : Optional("test+15@mailinator.com")}
        , {label: last name ; required: true ; type : string ; value : Optional("nsm")}
        ]}

你能提供获取数据并将其映射到对象的代码吗?我认为这将非常有用:@omar获取数据的代码只是对服务器的GET调用,我认为使用SwiftyJSON有点过分。仅仅为了执行简单的映射功能而添加整个库没有多大意义。你不需要你的json中没有任何数组。它只是一个带有属性的对象,但是为什么每个对象都是“Email”类型的?你实际上是如何从
init(来自decoder:decoder)对它进行解码的
函数在您的情况下,不需要强制执行init。电子邮件只是一个可编码的结构。您可以为它命名任何东西。如果它确实有效,请接受我的回答,并始终使用JSONParser以简化您的操作。
数据类
没有理由实现
编码键
(当它是结构时,不应将其命名为类)。您可以简单地将解码器的
keyDecodingStrategy
设置为
convertFromSnakeCase
对不起@andesta.erfan。我不能接受这个答案,因为它没有回答我的问题。如果我想要这样的东西,我可以访问任何JSONParser网站。我的问题专门询问数据对象。