计算中的BOOL属性使用valueForKey返回带有incorect值的NSNumber:

时间:2014-04-29 08:51:56

标签: ios objective-c kvc

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

[self.flags integerValue] & SomeConstantFlag

获取属性@property (readonly, nonatomic, assign) BOOL someConstantFlag

这在访问基础bool值(如

)时工作正常
model.someConstantFlag

但是当我尝试

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

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

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

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

3 个答案:

答案 0 :(得分:0)

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

来自documentation(强调我的):

  

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

     

valueForKey:确定了特定的访问方法或   实例变量,用于提供指定的值   key,它检查返回类型或数据类型。如果值是   返回的不是对象,创建了NSNumberNSValue对象   为该值而返回。

您的方法的返回值为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。

答案 1 :(得分:0)

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

BOOL boolVal = [value boolValue];

答案 2 :(得分:0)

我认为你应该考虑以下问题。首先,integerValue返回NSInteger,这意味着如果你支持64Bit架构,它将返回int_64而不是int_32,这里的代码更多

    [self.flags integerValue] & SomeConstantFlag

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

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

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

并在你的setter中查看以下内容

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

已经设置了标志kWhite,kBlue,kRed和kYellow。

但是,还没有设置kBrown。