How can I prevent myself from accidentally using an NSNumber's pointer when I want its intValue?
-
19-09-2019 - |
Question
One feature of Java that I really like is autoboxing, in which the compiler automatically converts between primitives and their wrapper classes.
I'm writing a Core Data application in Objective-C/Cocoa, and I'm finding it frustrating to deal with my integer attributes programmatically. Here's why:
//img is a managed object that I have fetched
NSString* filename = [NSString stringWithFormat:@"image%d.png", [[img valueForKey:@"imageID"] intValue]];
If I happen to forget the intValue
message, which I sometimes do, then the int that gets passed to stringWithFormat:
is actually the pointer value.
The problem is that this happens totally silently--no compiler error or warning. Sometimes I'll spend way too long debugging when this silly, stupid thing is the problem.
Is there a way to change my programming style or my compiler settings to prevent me from getting caught in that trap?
Edit: I wasn't clear about the fact that the above example is just one of many places where I run into trouble. Here's another hypothetical example that doesn't have to do with strings:
Entity CollegeClass
has two integer attributes: courseNumber
and enrollmentLimit
. Let's say I want to compare course numbers:
//classFoo is a NSManagedObjects I've fetched
if ([[classFoo valueForKey@"courseNumber"] intValue] < 400) {
NSLog(@"undergraduate class");
}
Or similarly, suppose I want to compute the average enrollment limit for all the classes in the CS department.
Solution
… suppose I want to compute the average enrollment limit for all the classes in the CS department.
This is easy to do with NSArray's and NSSet's @avg
operator. Of course, that will return an NSNumber, which puts you back in problem #2:
Let's say I want to compare course numbers:
//classFoo is a NSManagedObjects I've fetched if ([[classFoo valueForKey@"courseNumber"] intValue] < 400) { NSLog(@"undergraduate class"); }
I assume you mean that the problem you risk is omitting the intValue
message, thereby comparing the NSNumber object's id
to the int
.
The compiler offers a warning for such comparisons. In Xcode, add -Wextra
to your “Other C Flags” build setting. For more warning options, see the full list of GCC warnings.
OTHER TIPS
You can use %@ to convert a NSNumber directly to a string instead of the %d.
It will actually take any NSObject based class and convert it to a string I believe.
This is only applicable when dealing with Core Data, but if you use MOGenerator to generate classes for your Core Data objects (which I'd recommend doing anyway), you can then use -[propertyName]Value
methods to directly access the correct value for properties which return NSNumber
s:
// These two methods are identical when called on a class
// which was generated with MOGenerator
[[object imageID] intValue];
[object imageIDValue];
Turn on the “Typecheck calls to printf
/scanf
” warning, if it isn't on already. This doesn't currently help with NS/CFString formatting, but I've filed a Radar enhancement request (x-radar://problem/7375186) for that. You're welcome to file your own, of course.