BOOL values not recognized on CoreData objects - objective-c

I encountered a strange problem regarding CoreData and boolean values:
In my data model I have set an entity's property to BOOL. Later I set theEntity.theBooleanValue = [NSNumber numberWithBool:NO] and save the object. So far so good, but when I try to check for the saved property's value with if ([theObject valueForKey:#"theBooleanValue"] == [NSNumber numberBOOL:NO]){//do something} it never jumps into the if clause. But if I check for == [NSNumber numberWithInt:0] its working... so basically I try to save a bool but it's recognized as an int... Any ideas what's going on there?

It makes more sense to examine [[theObject valueForKey:#"theBooleanValue"] boolValue] for me. i.e.,
if(![[theObject valueForKey:#"theBooleanValue"] boolValue])
{
// Your code
}
I think == operator compares the object pointer, and not the number itself. To compare number there is a separete method [NSNumber isEqualToNumber:].

Note, that'll make your life a lot easier of you declare the properties like
#property (nonatomic) BOOL theBooleanValue;
This will allow you to use
if (!theObject.theBooleanValue) {
// Your code here
}
And you can assign directly with
theObject.theBooleanValue = YES;

Related

Safest way in getting intvalue of an object

Simple question [Objective-C]: (Couldn't find any solution till now).
I'm aware of [id intValue];. However this crashes my app because NSString can be <Null> sometimes, in my app. I can easily perform a check whether this is ` or not and then take decision accordingly. However I have many such situations (not recursive to use for or so) and was wondering what is the best possible way to make sure that my app doesn't crash.
Any Help is sincerely appreciated.
EDIT:
In my situation, I get a JSON Response from my server. and I create a NSDictionary from it. However, in my response I may get <NSNull> (Exactly like this, Due to a problem in the server API. Objective-C consider this (id) as NSNull class. What should I look for in this kind of situations?
There is two most common ways:
First method:
Check, wether string can actually respond to intValue. Or check if it's NSString or NSNumber.
NSString *string = ...;
int intValue = ([string respondsToSelector:#selector(intValue)]) ? [string intValue] : 0;
For convenience you can write a macros for this
#define intValueFromAnyObject(obj) ([obj respondsToSelector:#selector(intValue)]) ? [obj intValue] : 0;
int intValue = intValueFromAnyObject(string);
Second way (I like it much more):
Write a category on NSNull so it won't crash when you send it an unrecognized selector (intValue for example)
#interface NSNull (myExtension)
- (int)intValue;
#end
#implementation NSNull (myExtension)
- (int)intValue
{
return 0;
}
#end
From now on any time you'll try to get intValue from an NSNull object, you will get 0.
int value = (string) ? [string intValue] : 0;
0 or other return value when string is nil

Obj-C: using mutable and returning non mutable classes in methods

In objective-C I find myself creating alot of Mutable objects and then returning them as non mutable objects. Is the way I am doing it here, simply returning the NSMutableSet as an NSSet a good practice? I was thinking maybe I should specify that i make a copy of it.
/** Returns all the names of the variables used in a given
* program. If non are used it returns nil */
+ (NSSet *)variablesUsedInProgram:(id)program
{
NSMutableSet* variablesUsed = [[NSMutableSet alloc]init];
if ([program isKindOfClass:[NSArray class]]) {
for (NSString *str in program)
{
if ([str isEqual:#"x"] || [str isEqual:#"y"] || [str isEqual:#"a"] || [str isEqual:#"b"])
[variablesUsed addObject:str];
}
}
if ([variablesUsed count] > 0) {
return variablesUsed;
} else {
return nil;
}
}
If I were you, I would do it this way.
+ (NSSet *)variablesUsedInProgram:(id)program
{
NSSet *variablesUsed;
if ([program isKindOfClass:[NSArray class]]) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF = 'x' or SELF = 'y' or SELF = 'z'"];
variablesUsed = [NSSet setWithArray:[program filteredArrayUsingPredicate:predicate]];
}
int count;
return (count = [variablesUsed count]) > 0 ? variablesUsed : nil;
}
I find using predicate to filter array quite comprehensive and easy. Rather than dealing with creating a new mutable type and then testing certain condition, adding until the loop; in this scenario, it seems to be easier to use predicate. Hope this helps you.
It depends how much safety you require. If you return the object as an NSSet it will still be an NSMutableSet, so it could easily be cast back to one and modified.
Certainly, if you're creating a public API, I'd recommend returning a copy. For in internal project, perhaps the method signature already makes the intention clear enough.
Its, worth noting that, generally the performance impact of returning a copy is negligible - copying an immutable instance is effectively free whereas each copy sent to a mutable-passing-as-immutable will create another copy. So I would say its good practice to default to.
No. This is an absolutely correct OOP approach (it takes advantage of polymorphism). Every NSMutableSet is a proper NSSet. Don't copy superfluously.
Not a full answer here, consider NSProxy's one, but I want to clarify something.
In your case you create your object from scratch, and you don't set any ivar to point to that object. In my opinion in a good percentage of cases you don't need to make a copy of the mutable object returned. But if there is a good reason to deny the class client from mutating the class, then you should copy the variable.
Consider a property like this:
#property (nonatomic,assign) NSSet* set;
The class client could do this:
NSMutableSet* set= ... ; // inizialized to some value
classInstance.set= set;
// Mutate the set
Once mutated the set it could make the class be in an inconsistent state.
That's why when I have a property with the type of a class that has also a mutable version, I always put copy instead of assign in the property.

Use of #synthesize and value class type checking

This is probably a long shot, but I've got objects with a lot of properties. The values of these objects are populated from NSDictionary's created from a database request. Because of this, there may be NSNull values contained in those NSDictionaries that will automatically get assigned to the properties. I need the properties to automatically discard values/objects that aren't of the correct type. Currently I do it like this:
- (void) setViewID:(NSString *)viewID{
if (!viewID || [viewID isKindOfClass:[NSString class]]) _viewID = viewID;
}
But that ends up being a lot of extra code when I've got 30-50 properties. Is there a way to synthesize this behavior? It seems like it would be a common enough requirement, but I can't seem to find a way to do it aside from writing it all out.
Why not check for NSNull when you are going through the dictionary? E.g.
for (NSString *key in dictionary) {
id value = [dictionary objectForKey:key];
if (value == [NSNull null]) {
value = nil;
}
[self setValue:value forKey:key];
}

Why this strange behavior is occurring with this code? objective-c

I have a method (the code below is a simplified version) that parses small text files:
- (void)parseFile:(NSString *)aFile
{
NSDate *date;
NSNumber *number;
NSString *desc;
NSString *txt = [NSString stringWithContentsOfFile:aFile encoding:NSUTF8StringEncoding error:nil];
for (NSString *line in [txt componentsSeparatedByString:#"\n"]) {
if ([linesubstring isEqual:#"mydate"]) {
date = [dateFormat dateFromString:strDate];
}
if ([linesubstring isEqual:#"mynumber"]) {
number = [numberFormat numberFromString:strValue];
}
if ([linesubstring isEqual:#"mydesc"]) {
desc = [line substringWithRange:NSMakeRange(0, 10)];
}
if (!date && !number && !desc) {
...do something...
}
}
}
The first problem is that date variable is being filled with the content of aFile parameter. It only assumes it's correct value, when the passes through the fist if/check.
So why? I though that date could be a reserved word and exchanged it, but with the same behavior.
The second problem is with the last if (with the nested ones). Debuging the code, i can see that xcode shows it as "out of scope", but !number fails (xcode thinks that it's valid)...
I tried other combinations, like [number isNotEqualTo:[NSNull null]] (this one throws an error EXC_BAD_ACCESS), without success.
Please, could anybody give some hints? I'm newbie with cocoa/objective-c. I'm coming from java...
TIA,
Bob
There's quite a few things wrong with the code you've provided. I'm using the answer box because there isn't enough room for this to be a comment:
With regards to your variable declarations:
NSDate *date;
NSNumber *number;
NSString *desc;
You have correctly declared them, but you have not initialised them. As they are, they could be pointing to any random garbage. This means that your test at the end of the loop…
if (!date && !number && !desc) {
...do something...
}
…may in fact always execute because date, number and desc may always be non-zero (I say may because it is actually undefined whether they are zero or non-zero). Initialise each of them to nil if you plan to determine whether they are set or not:
NSDate *date = nil;
NSNumber *number = nil;
NSString *desc = nil;
It is not always necessary to initialise variables (for example, as long as you write to it before you read from it, it is not necessary to initialise it), however some people promote the idea of initialising all variables to prevent this undefined behaviour from surfacing (I typically initialise all variables even if I overwrite the initialised value anyway).
Also, there is a variable called linesubstring but it is not declared anywhere in the code, similarly strDate, strValue are not declared anywhere either. It is important to know how these are declared and how these are used as they may similarly be pointing to garbage.

Objective-C dictionary inserting a BOOL

OK, I'm a little confused.
It's probably just a triviality.
I've got a function which looks something like this:
- (void)getNumbersForNews:(BOOL)news andMails:(BOOL)mails {
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setValue:news forKey:#"getNews"];
[parameters setValue:mails forKey:#"getMails"];...}
It doesn't matter whether I use setValue:forKey: or setObject:ForKey:, I'm always getting a warning:
"Passing argument 1 of set... makes pointer from integer without a cast"...
How on earth do I insert a bool into a dictionary?
Values in an NSDictionary must be objects. To solve this problem, wrap the booleans in NSNumber objects:
[parameters setValue:[NSNumber numberWithBool:news] forKey:#"news"];
[parameters setValue:[NSNumber numberWithBool:mails] forKey:#"mails"];
Objective-C containers can store only Objective-C objects so you need to wrap you BOOL in some object. You can create a NSNumber object with [NSNumber numberWithBool] and store the result.
Later you can get your boolean value back using NSNumber's -boolValue.
Modern code for reference:
parameters[#"getNews"] = #(news);
A BOOL is not an object - it's a synonym for an int and has 0 or 1 as its values. As a result, it's not going to be put in an object-containing structure.
You can use NSNumber to create an object wrapper for any of the integer types; there's a constructor [NSNumber numberWithBool:] that you can invoke to get an object, and then use that. Similarly, you can use that to get the object back again: [obj boolValue].
You can insert #"YES" or #"NO" string objects and Cocoa will cast it to bool once you read them back.
Otherwise I'd suggest creating dictionary using factory method like dictionaryWithObjectsAndKeys:.
Seeing #Steve Harrison's answer I do have one comment. For some reason this doesn't work with passing object properties like for e.g.
[parameters setValue:[NSNumber numberWithBool:myObject.hasNews] forKey:#"news"];
This sets the news key to null in the parameter NSDictionary (for some reason can't really understand why)
My only solution was to use #Eimantas's way as follows:
[parameters setValue:[NSNumber numberWithBool:myObject.hasNews ? #"YES" : #"NO"] forKey:#"news"];
This worked flawlessly. Don't ask me why passing the BOOL directly doesn't work but at least I found a solution. Any ideas?