使用 JSONSerialization() 动态计算布尔值
Using JSONSerialization() to dynamically figure out boolean values
我从服务器(或文件)得到一个 JSON 字符串。
我想解析 JSON 字符串并 动态地 找出每个值类型。
但是,对于布尔值,JSONSerialization
只是将值转换为0
或1
,代码无法区分“0”是否为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
相关:
- How do I get NSJSONSerialization to output a boolean as true or false?
这种混乱是 "feature" 内置于 Swift<->Objective-C 桥中的所有奇妙魔法的结果。具体来说,is
和 as
关键字的行为方式与您预期的不同,因为 JSONSerialization
对象实际上是用 Objective-C 编写的,并没有存储这些数字作为 Swift Int
s、Double
s 或 Bool
s,而不是作为 NSNumber
对象,桥神奇地使 is
和as
将 NSNumber
转换为可以转换为的任何 Swift 数字类型。这就是为什么 is
为每个 NSNumber
类型提供 true
的原因。
幸运的是,我们可以通过将数字值转换为 NSNumber
来解决这个问题,从而避免桥接。从那里,我们 运行 进入 更多 桥接恶作剧,因为 NSNumber
是 toll-free 桥接到布尔值的 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")
}
}
当您使用 JSONSerialization
时,任何布尔值(true
或 false
)都会转换为 NSNumber
个实例,这就是使用 is Double
的原因、is Int
和 is Bool
全部 return 为真,因为 NSNumber
可以转换为所有这些类型。
您还会在 JSON.
中获得实际数字的 NSNumber
实例
但好消息是,在现实中,您实际上得到了 NSNumber
的特殊内部子类。布尔值实际上给你 __NSCFBoolean
,而实际数字给你 __NSCFNumber
。当然,您实际上并不想检查那些内部类型。
这是一个更完整的示例,显示了上述内容以及一个可行的解决方案,用于检查实际布尔值与 "normal" 数字。
let jsonString = "{\"boolean_key\" : true, \"int_key\" : 1}"
let jsonData = jsonString.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [String:Any]
print(type(of: json["boolean_key"]!)) // __NSCFBoolean
json["boolean_key"] is Double // true
json["boolean_key"] is Int // true
json["boolean_key"] is Bool // true
print(type(of: json["int_key"]!)) // __NSCFNumber
json["int_key"] is Double // true
json["int_key"] is Int // true
json["int_key"] is Bool // true
print(type(of: json["boolean_key"]!) == type(of: NSNumber(value: true))) // true
print(type(of: json["boolean_key"]!) == type(of: NSNumber(value: 1))) // false
print(type(of: json["int_key"]!) == type(of: NSNumber(value: 0))) // true
print(type(of: json["int_key"]!) == type(of: NSNumber(value: true))) // false
因为 JSONSerialization
将每个值转换为 NSNumber
,这可以通过尝试找出每个 NSNumber
实例下面的内容来实现:
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
(注意:我在输入时已经得到了类似的[更好的]答案,但我想把我的答案留给其他寻找不同方法的人)
我从服务器(或文件)得到一个 JSON 字符串。
我想解析 JSON 字符串并 动态地 找出每个值类型。
但是,对于布尔值,JSONSerialization
只是将值转换为0
或1
,代码无法区分“0”是否为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
相关:
- How do I get NSJSONSerialization to output a boolean as true or false?
这种混乱是 "feature" 内置于 Swift<->Objective-C 桥中的所有奇妙魔法的结果。具体来说,is
和 as
关键字的行为方式与您预期的不同,因为 JSONSerialization
对象实际上是用 Objective-C 编写的,并没有存储这些数字作为 Swift Int
s、Double
s 或 Bool
s,而不是作为 NSNumber
对象,桥神奇地使 is
和as
将 NSNumber
转换为可以转换为的任何 Swift 数字类型。这就是为什么 is
为每个 NSNumber
类型提供 true
的原因。
幸运的是,我们可以通过将数字值转换为 NSNumber
来解决这个问题,从而避免桥接。从那里,我们 运行 进入 更多 桥接恶作剧,因为 NSNumber
是 toll-free 桥接到布尔值的 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")
}
}
当您使用 JSONSerialization
时,任何布尔值(true
或 false
)都会转换为 NSNumber
个实例,这就是使用 is Double
的原因、is Int
和 is Bool
全部 return 为真,因为 NSNumber
可以转换为所有这些类型。
您还会在 JSON.
中获得实际数字的NSNumber
实例
但好消息是,在现实中,您实际上得到了 NSNumber
的特殊内部子类。布尔值实际上给你 __NSCFBoolean
,而实际数字给你 __NSCFNumber
。当然,您实际上并不想检查那些内部类型。
这是一个更完整的示例,显示了上述内容以及一个可行的解决方案,用于检查实际布尔值与 "normal" 数字。
let jsonString = "{\"boolean_key\" : true, \"int_key\" : 1}"
let jsonData = jsonString.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [String:Any]
print(type(of: json["boolean_key"]!)) // __NSCFBoolean
json["boolean_key"] is Double // true
json["boolean_key"] is Int // true
json["boolean_key"] is Bool // true
print(type(of: json["int_key"]!)) // __NSCFNumber
json["int_key"] is Double // true
json["int_key"] is Int // true
json["int_key"] is Bool // true
print(type(of: json["boolean_key"]!) == type(of: NSNumber(value: true))) // true
print(type(of: json["boolean_key"]!) == type(of: NSNumber(value: 1))) // false
print(type(of: json["int_key"]!) == type(of: NSNumber(value: 0))) // true
print(type(of: json["int_key"]!) == type(of: NSNumber(value: true))) // false
因为 JSONSerialization
将每个值转换为 NSNumber
,这可以通过尝试找出每个 NSNumber
实例下面的内容来实现:
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
(注意:我在输入时已经得到了类似的[更好的]答案,但我想把我的答案留给其他寻找不同方法的人)