我从服务器(或文件)获取JSON字符串。
我想解析那个JSON字符串,动态找出每个值类型。
但是,当涉及布尔值时,JSONSerialization
只是将值转换为0
或1
,代码无法区分是否" 0&# 34;是Double
,Int
或Bool
。
我想在没有明确知道特定键对应Bool
值的情况下识别该值是否为Bool
。我做错了什么,或者我能做些什么不同?
// What currently is happening:
let jsonString = "{\"boolean_key\" : true}"
let jsonData = jsonString.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as! [String:Any]
json["boolean_key"] is Double // true
json["boolean_key"] is Int // true
json["boolean_key"] is Bool // true
// What I would like to happen is below (the issue doesn't happen if I don't use JSONSerialization):
let customJson: [String:Any] = [
"boolean_key" : true
]
customJson["boolean_key"] is Double // false
customJson["boolean_key"] is Int // false
customJson["boolean_key"] is Bool // true
相关:
答案 0 :(得分:3)
这种混乱是Swift< - > Objective-C桥内置的所有奇妙魔法的“特征”的结果。具体来说,is
和as
关键字的行为不符合您的预期,因为JSONSerialization
对象实际上是用Objective-C编写的,而不是将这些数字存储为Swift Int
s,Double
或Bool
s,而是NSNumber
个对象,而网桥只是神奇地让is
和as
转换NSNumber
到任何可以转换为它们的Swift数字类型。这就是is
为每个true
类型提供NSNumber
的原因。
幸运的是,我们可以通过将数值转换为NSNumber
来解决这个问题,从而避免桥接。从那里开始,我们遇到了更多过渡性的恶作剧,因为NSNumber
免费为布尔人CFBoolean
和大多数其他事情CFNumber
。因此,如果我们跳过所有环节以达到CF水平,我们可以做以下事情:
if let num = json["boolean_key"] as? NSNumber {
switch CFGetTypeID(num as CFTypeRef) {
case CFBooleanGetTypeID():
print("Boolean")
case CFNumberGetTypeID():
switch CFNumberGetType(num as CFNumber) {
case .sInt8Type:
print("Int8")
case .sInt16Type:
print("Int16")
case .sInt32Type:
print("Int32")
case .sInt64Type:
print("Int64")
case .doubleType:
print("Double")
default:
print("some other num type")
}
default:
print("Something else")
}
}
答案 1 :(得分:3)
由于JSONSerialization
会将每个值转换为NSNumber
,因此可以通过尝试找出每个NSNumber
实例的内容来实现:https://stackoverflow.com/a/30223989/826435
let jsonString = "{ \"boolean_key\" : true, \"integer_key\" : 1 }"
let jsonData = jsonString.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as! [String:Any]
extension NSNumber {
var isBool: Bool {
return type(of: self) == type(of: NSNumber(booleanLiteral: true))
}
}
(json["boolean_key"] as! NSNumber).isBool // true
(json["integer_key"] as! NSNumber).isBool // false
(注意:我已经输入了类似的[更好]答案,但我想留下我的答案给其他人看不同的方法)
答案 2 :(得分:2)
当您使用JSONSerialization
时,任何Bool值(true
或false
)都会转换为NSNumber
个实例,这就是使用is Double
,{的原因{1}}和is Int
都返回true,因为is Bool
可以转换为所有类型。
您还可以获得JSON中实际数字的NSNumber
实例。
但好消息是,实际上,你实际上得到了NSNumber
的特殊内部子类。布尔值实际上为您提供NSNumber
,而实际数字为您提供__NSCFBoolean
。当然,您实际上并不想检查这些内部类型。
这是一个更全面的例子,显示上述以及一个可行的解决方案,以检查实际的布尔值与"正常"号。
__NSCFNumber