为什么 setValue:forKey: 在 32 位系统而不是 64 位系统上失败?

Why does setValue:forKey: fail on a 32-bit system but not 64-bit?

我最近向 Apple 提交了一份关于此的错误报告,但我想无论如何我都会问这个问题,以防我遗漏了一些明显的东西。在 Objective-C 中,以下调用在 64 位系统上运行良好,但在 32 位系统上抛出 NSInvalidArgumentException:

[self setValue:@"true" forKey:@"flag"];

"flag" 属性 是一个 BOOL:

@property BOOL flag;

此外,调用在 Swift/32-bit 中工作正常,其中 属性 是布尔值:

var flag: Bool = false

同样,此调用在 64 位系统上的 Swift 中工作正常,但在 32 位系统上抛出 NSInvalidArgumentException("index" 是一个 Int):

setValue("2", forKey: "index")

但它在 Objective-C/32-bit 中工作正常,其中 属性 是一个 NSInteger。

我希望这些调用能够正常工作,而不管语言或处理器体系结构如何。有没有人知道为什么他们可能不这样做?

如果你把它们全部结合起来,答案就在评论中...

setValue:forKey: not 是否需要 NSNumber/NSValue 用于原始类型的属性,但您通常会传递一个。

观察到的问题也没有下降到 64 位和 32 位,示例代码在 64 位系统上也可能失败。

这完全取决于 BOOL 的性质,以及它是 char 还是 bool,正如评论所暗示的那样 - 这取决于许多因素(来自 Xcode 6.4 运行 于 10.10.5):

/// Type to represent a boolean value.
#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

setValue:forKey 当设置原始类型 属性 时 调用 - <type>Value 对传递的任何对象。

如果 BOOL 是一个 char 它调用 - charValue,而 NSString 没有这样的方法 - 所以失败。

如果 BOOLbool,它调用 - boolValue,并且 NSString 有,所以一切都很好。

简单修复:

@property bool flag;

这应该适用于任何地方,并且有额外的好处,即 flag 总是 是 true/false、YES/NO、1/0 和不是 char 的其他 254 种可能性之一。

想想看,如果 C 的设计者不吝啬,而是从一开始就包含一个真正的布尔类型,事情会有多么不同...

上面@CRD提到,BOOL是char在32位设备上的typedef,而NSString没有charValue方法,所以我们可以添加一个简单的NSString类别来修复它,像这样。

#import "NSString+DCCharValue.h"

@implementation NSString (DCCharValue)

#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
#else
- (BOOL)charValue {
    return [self boolValue];
}
#endif

@end