是否有正确的方法来确定 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
}
包含 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
}