包含布尔值的NSNumber很容易与可以包装在NSNumber类中的其他类型的类型混淆:
NSNumber(bool:true).boolValue // true
NSNumber(integer: 1).boolValue // true
NSNumber(integer: 1) as? Bool // true
NSNumber(bool:true) as? Int // 1
NSNumber(bool:true).isEqualToNumber(1) // true
NSNumber(integer: 1).isEqualToNumber(true) // true
但是,保留了有关其原始类型的信息,如下所示:
NSNumber(bool:true).objCType.memory == 99 // true
NSNumber(bool:true).dynamicType.className() == "__NSCFBoolean" // true
NSNumber(bool:true).isEqualToValue(true) || NSNumber(bool:true).isEqualToValue(false) //true
问题是:这些方法中哪一种是确定布尔值何时被包裹在 NSNumber 中而不是其他东西的最佳(和/或最安全)方法?都同样有效吗?或者,有没有另一个更好的解决方案?
你可以对 Objective-C提出同样的问题,这里有一个 Objective-C 的答案 - 你可以从 Swift 调用或翻译成 Swift。
NSNumber
是免费桥接CFNumberRef
,这是另一种说法,即NSNumber
对象实际上是CFNumber
对象(反之亦然)。现在CFNumberRef
有一个布尔值的特定类型,CFBooleanRef
,这在创建布尔CFNumberRef
(又名NSNumber *
)时使用......因此,您需要做的就是检查您的NSNumber *
是否是CFBooleanRef
的实例:
- (BOOL) isBoolNumber:(NSNumber *)num
{
CFTypeID boolID = CFBooleanGetTypeID(); // the type ID of CFBoolean
CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num)); // the type ID of num
return numID == boolID;
}
注意:您可能会注意到,从布尔值创建的NSNumber
/CFNumber
对象实际上是预定义的常量对象;一个用于YES
,一个用于NO
。您可能会想依靠它来识别。然而,虽然目前似乎是真的,并且显示在Apple的源代码中,但据我们所知,它没有记录在案,所以不应该被依赖。
呵呵
补遗
快速代码翻译(通过 GoodbyeStackOverflow):
func isBoolNumber(num:NSNumber) -> Bool
{
let boolID = CFBooleanGetTypeID() // the type ID of CFBoolean
let numID = CFGetTypeID(num) // the type ID of num
return numID == boolID
}
第一个是正确的。
NSNumber
是一个Objective-C类。它是为Objective-C构建的。它使用Objective-C的类型编码存储类型。因此,在 Objctive-C 中,最好的解决方案是:
number.objCType[0] == @encoding(BOOL)[0] // or string compare, what is not necessary here
这可确保在重新编译后更改类型编码将起作用。
AFAIK 在 Swift 中没有@encoding()
。所以你必须使用文字。但是,这不会中断,因为@encoding()
在编译时被替换,并且更改编码会中断编译的代码。不可能。
第二种方法使用内部标识符。这可能是改变的主题。
我认为第三种方法会有误报。
不要依赖类名,因为它可能属于类集群,它是一个实现细节(因此可能会发生变化)。
不幸的是,Objective-CBOOL
类型最初只是 C 中signed char
的 typedef,它总是编码为c
(这是您看到的99
值,因为 ASCII 中的c
是 99)。
在现代 Objective-C 中,我相信BOOL
类型是一个实际的布尔类型(即不再只是signed char
的 typedef),但为了兼容性,当提供给@encode()
时,它仍然编码为c
。
因此,没有办法判断99
最初指的是signed char
还是BOOL
,就NSNumber
而言,它们是相同的。
也许如果你解释为什么你需要知道NSNumber
最初是否是一个BOOL
,可能会有更好的解决方案。