问题
I have a simple object which has one NSNumber which is used to store some flags. I have a conienience getter method which in fact does:
[self.flags integerValue] & SomeConstantFlag
for a property@property (readonly, nonatomic, assign) BOOL someConstantFlag
and this works fine when accesing the underlying bool value like
model.someConstantFlag
but when I try to
id value = [model valueForKey:@"someConstantFlag"];
Then it returns a bad boolean representation e.g. NSNumber with value 2, 4 etc. Why is this happening when the declaration of the property is BOOL? Is there a "Pretty" way to overcome this issue?
Wrapping on the other hand works ok:
BOOL someBool = 42;
NSNumber* numberVal = @(someBool);
//The underlying is an __NSCFBoolean with the proper 0/1 val!
回答1:
valueForKey
always returns an Objective-C object, even if the property has scalar type.
From the documentation (emphasis mine):
The default implementations of
valueForKey:
andsetValue:forKey:
provide support for automatic object wrapping of the non-object data types, both scalars and structs.Once
valueForKey:
has determined the specific accessor method or instance variable that is used to supply the value for the specified key, it examines the return type or the data type. If the value to be returned is not an object, anNSNumber
orNSValue
object is created for that value and returned in its place.
The return value of your method is BOOL
, which is defined as
typedef signed char BOOL;
on OS X and on the 32-bit iOS platform. So what valueForKey
returns is a NSNumber
containing the result of
signed char val = [self.flags integerValue] & SomeConstantFlag;
and that can be in the range -128 .. 127.
To ensure that you get only YES
or NO
(aka 1 or 0) write your custom getter as:
-(BOOL)someConstantFlag
{
return ([self.flags integerValue] & SomeConstantFlag) != 0;
}
Remark: On the 64-bit iOS platform (but not on 64-bit OS X), BOOL
is defined as the C99 _Bool
, which is a "proper" boolean type and can take only the value 0 or 1.
回答2:
NSNumber *value = @([model objectForKey:@"someConstantFlag"]);
BOOL boolVal = [value boolValue];
回答3:
I think you should consider the following problems. Firstly, integerValue returns NSInteger which means if you support 64Bit architecture it will return int_64 not int_32, what is more in your code here
[self.flags integerValue] & SomeConstantFlag
this does the following if flags is 00010 and somConstantFlags is 00001 the & of those will do something you probably does not expect because you will get value of 00000 which equals 0 or if they are 00011 and 00110 you will get 00010 which equals 2. So that is why when you call valueForKey you get 2 or 4 or something else depending on your flags :) What is more in objective-C everything different then 0 is YES.
Try reconsidering your bit logic :). See The following example
enum
{
kWhite = 0,
kBlue = 1 << 0,
kRed = 1 << 1,
kYellow = 1 << 2,
kBrown = 1 << 3,
};
typedef char ColorType;
and in your setter check the following
ColorType pinkColor = kWhite | kRed;
if (pinkColor & (kWhite | kBlue | kRed | kYellow)) {
// any of the flags has been set
}
The flags kWhite, kBlue, kRed and kYellow have been set.
However, kBrown has not been set.
来源:https://stackoverflow.com/questions/23359925/bool-property-from-a-calculation-returns-nsnumber-with-incorect-value-using-valu