我在Swift 4.2中无法解析JSON。以下代码显示了运行时错误。
我从服务器获取的Json数据如下。
{
code: 406,
message: "Email Address already Exist.",
status: 0
}
我正在使用Codable来创建我的结构,如下所示
struct Registration: Codable {
var code: Int
var status: Int
private enum CodinggKeys: String, CodingKey {
case code
case status
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
self.code = Int(try container.decode(String.self, forKey: .code))!
} catch DecodingError.typeMismatch {
let value = try container.decode(Double.self, forKey: .code)
self.code = Int(value);
}
do {
self.status = try container.decode(Int.self, forKey: .status)
} catch DecodingError.typeMismatch {
let value = try container.decode(String.self, forKey: .status)
self.status = Int(value);
}
}
}
但是每次我在解析状态键时遇到错误。
注意:我曾尝试解析 String,Int,Double,Decimal,NSInterger 中的状态,但均无效。每次我遇到相同的错误。 希望对UInt进行解码,但是找到了一个数字。
答案 0 :(得分:10)
该错误消息非常容易引起误解。当JSON包含布尔值并且该结构具有对应键的Int属性时,就会发生这种情况。
您的JSON 实际上很可能像这样:
{
"code": 406,
"message": "Email Address already Exist.",
"status": false
}
,因此,您的结构应为
struct Registration: Codable {
let code: Int
let status: Bool
}
if let registration = try? JSONDecoder().decode(Registration.self, from: data) {
print(registration.code) // 406
print(registration.status) // false
}
答案 1 :(得分:1)
如果结构的属性已经为Decodable
,则无需实现自己的解码初始化程序。您也不需要@Gereon提到的自定义CodingKeys
。
对于以下JSON数据:
let data = """
{
"code": 406,
"message": "Email Address already Exist.",
"status": 0
}
""".data(using: .utf8)!
这很好:
struct Registration: Codable {
var code: Int
var status: Int
}
if let registration = try? JSONDecoder().decode(Registration.self, from: data) {
print(registration.code) // 406
print(registration.status) // 0
}
有关详情,请参阅Apple的Encoding and Decoding Custom Types。
答案 2 :(得分:1)
我认为我们可以使用它来解决此类问题:
protocol DecodingHelper {
associatedtype Keys: CodingKey
static func getStringValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> String
static func getIntValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Int
static func getBoolValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Bool
}
extension DecodingHelper {
static func getStringValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> String {
var str: String = ""
if let obj = try? container.decode(String.self, forKey: key) {
str = obj
}
else if let obj = try? container.decode(Int.self, forKey: key){
str = String(obj)
}
return str
}
static func getIntValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Int {
var val: Int = 0
if let obj = try? container.decode(String.self, forKey: key),
let intVal = Int(obj){
val = intVal
}
else if let obj = try? container.decode(Int.self, forKey: key){
val = obj
}
return val
}
static func getBoolValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Bool {
var val: Bool = false
if let obj = try? container.decode(String.self, forKey: key),
let intVal = Int(obj){
(intVal != 0) ? (val = true) : (val = false)
}
else if let obj = try? container.decode(Int.self, forKey: key){
(obj != 0) ? (val = true) : (val = false)
}
else if let obj = try? container.decode(Bool.self, forKey: key){
val = obj
}
return val
}
}
struct VideoFeedback: Codable {
// MARK:- Variables -
var isFeedbackProvided:Bool = true
// MARK:- Initialisation -
private enum CodingKeys: String, DecodingHelper, CodingKey {
typealias Keys = CodingKeys
case isFeedbackProvided = "lastVideoFeedback"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
isFeedbackProvided = CodingKeys.getBoolValue(values, key: .isFeedbackProvided)
}
}
如果您有任何改善建议,请告诉我。
答案 3 :(得分:0)
对于此类问题,请检查并确保结构中给出的响应和响应类型相同。在这里,您的回答似乎不正确。状态可能为真或假
SoapFault: Could not connect to host
如果状态为true,则将结构更改为
{
code: 406,
message: "Email Address already Exist.",
status: 0
}
如果状态为0,则在上述结构中将struct Registration: Codable {
var code: Int
var status: Bool
var message: String
}
更改为var status: Bool
。