是否有正确的方法来确定 NSNumber 是使用 Swift 从 Bool 派生的?

Is there a correct way to determine that an NSNumber is derived from a Bool using Swift?

包含 Bool 的 NSNumber 很容易与可以包含在 NSNumber 中的其他类型混淆 class:

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

问题是:在确定 Bool 何时包含在 NSNumber 而不是其他东西中时,这些方法中哪一种是最好的(and/or 最安全的)方法?都同样有效吗?或者,还有其他更好的解决方案吗?

第一个是正确的。

NSNumber 是一个 Objective-C class。它是为 Objective-C 构建的。它使用 Objective-C 的类型编码存储类型。所以在 Objctive-C 中最好的解决方案是:

number.objCType[0] == @encoding(BOOL)[0] // or string compare, what is not necessary here

这确保了类型编码的更改在重新编译后有效。

据我所知,您在 Swift 中没有 @encoding()。所以你必须使用文字。但是,这不会中断,因为 @encoding() 在编译时被替换并且更改编码会破坏编译代码。不太可能。

第二种方法使用内部标识符。这可能会发生变化。

我认为第三种方法会有误报。

不要依赖 class 名称,因为它可能属于 class 集群,并且它是一个实现细节(因此可能会发生变化)。

不幸的是,Objective-C BOOL 类型最初只是 C 中 signed char 的类型定义,它总是编码为 c(这是 99 您看到的值,因为 ASCII 中的 c 是 99).

在现代 Objective-C 中,我相信 BOOL 类型是一个实际的布尔类型(即不再只是 signed char 的类型定义)但为了兼容性,它仍然编码为 c 当给 @encode().

因此,无法判断 99 最初指的是 signed char 还是 BOOL,就 NSNumber 而言,它们是相同的.

如果你解释一下为什么你需要知道 NSNumber 最初是否是 BOOL,也许会有更好的解决方案。

您可以针对 Objective-C 提出相同的问题,这里是 Objective-C 中的答案 - 您可以调用或翻译成 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's source code 中,但据我们所知,它 未记录,因此不应依赖。

HTH

附录

Swift 代码翻译(来自 GoodbyeWhosebug):

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
}