kga*_*dis 8 ios swift swift4.1
我从服务器(或文件)获取 JSON 字符串。
我想解析那个 JSON 字符串并动态找出每个值类型。
然而,当涉及到布尔值,JSONSerialization
只需将值转换为0
或1
,并且代码不能区分是否为“0”是一个Double
,Int
或Bool
。
我想在Bool
不明确知道特定键对应于Bool
值的情况下识别该值是否为 a 。我做错了什么,或者我可以做些什么不同的事情?
// 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
Run Code Online (Sandbox Code Playgroud)
有关的:
这种混乱是 Swift<->Objective-C 桥接器中内置的所有奇妙魔法的“特性”的结果。具体来说,is
andas
关键字的行为与您期望的方式不同,因为JSONSerialization
对象实际上是用 Objective-C 编写的,不是将这些数字存储为 Swift Int
s、Double
s 或Bool
s,而是存储为NSNumber
对象,而桥梁神奇地让is
和as
转换NSNumber
S到任何斯威夫特数字类型,它们可以转换为。所以这就是为什么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")
}
}
Run Code Online (Sandbox Code Playgroud)
当您使用JSONSerialization
,任何布尔值(true
或false
)转换为:NSNumber
实例这就是为什么使用的is Double
,is Int
以及is Bool
一切回归无疑的,因为NSNumber
可以转换为所有类型的。
您还可以获得NSNumber
JSON 中实际数字的实例。
但好消息是,实际上,您实际上获得了NSNumber
. 布尔值实际上给你,__NSCFBoolean
而实际数字给你__NSCFNumber
。当然,您实际上并不想检查这些内部类型。
这是一个更完整的示例,显示了上述内容以及检查实际布尔值与“正常”数字的可行解决方案。
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
Run Code Online (Sandbox Code Playgroud)
因为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
Run Code Online (Sandbox Code Playgroud)
(注意:我在打字时已经得到了类似的 [更好] 答案,但我想把我的答案留给其他寻找不同方法的人)
归档时间: |
|
查看次数: |
1988 次 |
最近记录: |