类型正确时,可解码类型上的typeMismatch

时间:2018-08-20 04:31:29

标签: json swift codable decodable

当我用Postman打我的配置API时,会得到以下json响应。在此响应中,两个apiVersion键是数字而不是字符串。

{
    "data": {
        "availability": {
            "auth": true,
            "ab": true,
            "cd": true
        },
        "helloWorldConfiguration": {
            "apiKey": "abcefg",
            "rootUrl": "https://foo",
            "apiVersion": 3
        },
        "fooBarConfiguration": {
            "baseUrl": "https://foo",
            "apiVersion": 1,
            "privateApiPath": "",
            "publicApiPath": "dev",
            "tokenPath": ""
        }
    },
    "errors": []
}

当我尝试对其进行解码时,它失败,并显示typeMismatch错误。当我输出响应的内容时,我看到以下内容对我来说很好。

data = {
    availability = {
        auth = 1;
        ab = 1;
        cd = 1;
    };
    helloWorldConfiguration = {
        apiVersion = 1;
        baseUrl = "https://foo";
        privateApiPath = "";
        publicApiPath = dev;
        tokenPath = "";
    };
    fooBarConfiguration = {
        apiKey = abcefg;
        apiVersion = 3;
        rootUrl = "https://foo";
    };
};
errors =     (
);

给我的错误表明data.helloWorldConfiguration.apiVersion的类型为string而不是int。我们可以从邮递员那里得到的原始HTTP响应中看到情况并非如此。

  

typeMismatch(Swift.Int,Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue:“ data”,intValue:nil),CodingKeys(stringValue:“ helloWorldConfiguration”,intValue:nil),CodingKeys(stringValue:“ apiVersion “,intValue:nil)],debugDescription:”预期对Int进行解码,但找到了一个字符串/数据。“,底层错误:nil))   21:17:40错误无法将响应数据解码为模型表示形式。

我的模型将这些属性表示为整数,这样看来它会收到响应,并认为这些数字是字符串,不是。

public struct ServerConfiguration: Decodable {
    let availability: AvailabilityConfiguration
    let helloWorldConfiguration: HelloWorldConfiguration
    let fooBarConfiguration: FooBarConfiguration

    init(availability: AvailabilityConfiguration, helloWorldConfiguration: HelloWorldConfiguration, fooBarConfiguration: FloatSinkConfiguration) {
        self.availability = availability
        self.helloWorldConfiguration = helloWorldConfiguration
        self.fooBarConfiguration = fooBarConfiguration
    }
}

public struct FooBarConfiguration: Decodable {
    let baseUrl: String
    let apiVersion: Int
    let privateApiPath: String
    let publicApiPath: String
    let tokenPath: String

    init(baseUrl: String, apiVersion: Int, privateApiPath: String, publicApiPath: String, tokenPath: String) {
        self.baseUrl = baseUrl
        self.apiVersion = apiVersion
        self.privateApiPath = privateApiPath
        self.publicApiPath = publicApiPath
        self.tokenPath = tokenPath
    }
}

public struct AvailabilityConfiguration: Decodable {
    let auth: Bool
    let ab: Bool
    let cd: Bool

    init(auth: Bool, ab: Bool, cd: Bool) {
        self.auth = auth
        self.ab = ab
        self.cd = cd
    }
}

public struct HelloWorldConfiguration: Codable {
    let apiKey: String
    let rootUrl: String
    let apiVersion: Int

    init(apiKey: String, rootUrl: String, apiVersion: Int) {
        self.apiKey = apiKey
        self.rootUrl = rootUrl
        self.apiVersion = apiVersion
    }
}

如您所见,我的apiVersion成员和json响应都是整数类型。我在这里做错了什么?我假设发生的事情是Swift正在考虑json字符串中的数字,而不管它们在json中的实际表示方式如何。是这样吗?

编辑以显示Alamofire响应数据的utf8字符串

21:44:06 INFO GET: https:foo/configuration
{
    "data" : {
        "availability" : {
            "auth" : true,
            "ab" : true,
            "cb" : true
        },
        "helloWorldConfiguration" : {
            "apiKey" : "abcd",
            "rootUrl" : "https://foo",
            "apiVersion" : "3"
        },
        "fooBarConfiguration" : {
            "baseUrl" : "https://foo",
            "apiVersion" : "1",
            "privateApiPath" : "",
            "publicApiPath" : "dev",
            "tokenPath" : "auth/token"
        }
    },
    "errors" : []
}

看来,尽管API正确返回了apiVersion作为数字,但是Swift还是将其转换为字符串。我解码不正确吗?

func getRoute<TResponseData: Decodable>(route:String, completion: @escaping (TResponseData) -> Void) throws {
    let headers = try! self.getHeaders(contentType: ContentType.json)
    let completeUrl: String = self.getUrl(route: route, requestUrl: nil)
    logger.info("GET: \(completeUrl)")
Alamofire.request(
    completeUrl,
    method: .get,
    parameters: nil,
    encoding: JSONEncoding.default,
    headers: headers)
    .validate()
    .responseJSON { (response) -> Void in
        self.logger.info("GET Response: \(String(describing:response.response?.statusCode))")

        switch response.result {
        case .success(_):
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .custom(Date.toFooBarDate)
            do {
                let result = try decoder.decode(TResponseData.self, from: response.data!)
                completion(result)
            } catch DecodingError.dataCorrupted(let error) {
                self.logger.error(error.underlyingError!)
                return
            } catch {
                print(response.result.value!)
                print(error)
                self.logger.error("Unable to decode the response data into a model representation.")
                return
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

我在操场上检查了一下,看来一切正常。要找到真正的问题,我认为您需要提供获取json的真实网址,并可以使用alamofire进行检查

import Foundation
let json = """
{
"data": {
    "availability": {
        "auth": true,
        "ab": true,
        "cd": true
    },
    "helloWorldConfiguration": {
        "apiKey": "abcefg",
        "rootUrl": "https://foo",
        "apiVersion": 3
    },
    "fooBarConfiguration": {
        "baseUrl": "https://foo",
        "apiVersion": 1,
        "privateApiPath": "",
        "publicApiPath": "dev",
        "tokenPath": ""
    }
},
"errors": []
 }
 """
let data = json.data(using: .utf8)


struct Response : Codable {
let data : Data?
let errors : [String]?
 }
 struct Availability : Codable {
let auth : Bool?
let ab : Bool?
let cd : Bool?
 }

 struct Data : Codable {
let availability : Availability?
let helloWorldConfiguration : HelloWorldConfiguration?
let fooBarConfiguration : FooBarConfiguration?
 }

struct FooBarConfiguration : Codable {
let baseUrl : String?
let apiVersion : Int?
let privateApiPath : String?
let publicApiPath : String?
let tokenPath : String?
}
struct HelloWorldConfiguration : Codable {
let apiKey : String?
let rootUrl : String?
let apiVersion : Int?
}


 let decoder = JSONDecoder()

 let response = try decoder.decode(Response.self, from: data!)
 print(response)

这是回应

响应(数据:可选(__lldb_expr_11.Data(可用性:可选(__lldb_expr_11.Availability(auth:可选(true),ab:可选(true),cd:可选(true)))),helloWorldConfiguration:可选(__lldb_expr_11。 HelloWorldConfiguration(apiKey:Optional(“ abcefg”),rootUrl:Optional(“ https://foo”),apiVersion:Optional(3))),fooBarConfiguration:Optional(__ lldb_expr_11.FooBarConfiguration(baseUrl:Optional(“ {{3}) }“),apiVersion:可选(1),privateApiPath:可选(”“),publicApiPath:可选(” dev“),tokenPath:可选(”“))))))),错误:可选([]))