1

我有一个简单的对象,它有一个 NSNumber 用于存储一些标志。我有一个 conienience getter 方法,它实际上可以:

[self.flags integerValue] & SomeConstantFlag

对于一个属性@property (readonly, nonatomic, assign) BOOL someConstantFlag

这在访问基础布尔值时可以正常工作

model.someConstantFlag

但是当我尝试

id value = [model valueForKey:@"someConstantFlag"];

然后它返回一个错误的布尔表示,例如值为 2、4 等的 NSNumber。为什么当属性声明为 BOOL 时会发生这种情况?有没有一种“漂亮”的方法来克服这个问题?

另一方面,包装工作正常:

BOOL someBool = 42;
NSNumber* numberVal = @(someBool);
//The underlying is an __NSCFBoolean with the proper 0/1 val!
4

3 回答 3

0
NSNumber *value = @([model objectForKey:@"someConstantFlag"]);

BOOL boolVal = [value boolValue];
于 2014-04-29T09:02:47.330 回答
0

valueForKey始终返回一个 Objective-C 对象,即使该属性具有标量类型。

文档(强调我的):

默认实现valueForKey:setValue:forKey: 提供对非对象数据类型(标量和结构)的自动对象包装的支持。

一旦valueForKey:确定了用于为指定键提供值的特定访问器方法或实例变量,它就会检查返回类型或数据类型。如果要返回的值不是对象,则为该值创建一个NSNumberorNSValue对象 并在其位置返回。

您的方法的返回值为 ,BOOL定义为

typedef signed char BOOL;

在 OS X 和 32 位 iOS 平台上。所以valueForKey返回的是一个NSNumber 包含结果的

signed char val = [self.flags integerValue] & SomeConstantFlag;

并且可以在 -128 .. 127 的范围内。

为确保您仅获得YESNO(又名 1 或 0)将您的自定义 getter 编写为:

-(BOOL)someConstantFlag
{
    return ([self.flags integerValue] & SomeConstantFlag) != 0;
}

备注:在 64 位 iOS 平台上(但不是在 64 位 OS X 上),BOOL被定义为 C99 _Bool,这是一个“正确的”布尔类型,只能取值 0 或 1。

于 2014-04-29T08:59:42.047 回答
0

我认为你应该考虑以下问题。首先,integerValue 返回 NSInteger,这意味着如果您支持 64 位架构,它将返回 int_64 而不是 int_32,您的代码中还有什么

    [self.flags integerValue] & SomeConstantFlag

如果 flags 为 00010 且 somConstantFlags 为 00001,则执行以下操作,其中的 & 将执行您可能不会想到的事情,因为您将获得 00000 的值,等于 0,或者如果它们是 00011 和 00110,您将获得 00010,等于 2。所以这就是为什么当你调用 valueForKey 时,你会得到 2 或 4 或其他取决于你的标志的东西:) 在 Objective-C 中更重要的是,一切都不同,然后 0 是 YES。

尝试重新考虑您的位逻辑:)。请参阅以下示例

    enum 
    {
    kWhite   = 0,
    kBlue    = 1 << 0,
    kRed     = 1 << 1,
    kYellow  = 1 << 2,
    kBrown   = 1 << 3,
    };
    typedef char ColorType;

并在您的设置器中检查以下内容

ColorType pinkColor = kWhite | kRed;
if (pinkColor & (kWhite | kBlue | kRed | kYellow)) {
// any of the flags has been set
}

已设置标志 kWhite、kBlue、kRed 和 kYellow。

但是,kBrown 尚未设置。

于 2014-04-29T09:13:57.950 回答