有没有正确的方法可以使用 Swift 确定 NSNumber 是从布尔值派生出来的?



包含布尔值的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,可能会有更好的解决方案。

最新更新