为什么 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
没有这样的方法 - 所以失败。
如果 BOOL
是 bool
,它调用 - 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
我最近向 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
没有这样的方法 - 所以失败。
如果 BOOL
是 bool
,它调用 - 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