Today I was reviewing some code and I have been totally fooled. I saw something like this in the code
...
NSNumber *myNumber = [NSNumber numberWithInteger:4];
...
if (myNumber == [NSNumber numberWithInteger:4)
{
...
}
...
When I read that if condition, my first thought was: waw man! how can you do that? You are obviously comparing pointers here, so of course the code in this if will never be executed as you are generating an instance in the right place, so the objects will never be the same!
My (big) surprise was that actually the if was being executed! So I generated some tests to deepen in what what was going on, and I got this:
NSInteger intValue = 5;
NSNumber *anIntNumber = [NSNumber numberWithInteger:intValue];
NSNumber *anotherIntNumber = [NSNumber numberWithInteger:intValue];
NSLog(#"%p vs %p -> %#", anIntNumber, anotherIntNumber, ((anIntNumber == anotherIntNumber) ? #"YES" : #"NO"));
This is the result:
0x7462560 vs 0x7462560 -> YES
So I then remembered that I read somewhere here in stack overflow that constant NSString were stored somewhere in the memory stack when a program begins. So then I run this code to check if the same thing was happening with NSString instances:
NSString *aString = #"FOO";
NSString *anotherString = #"FOO";
NSLog(#"%p vs %p -> %#", aString, anotherString, ((aString == anotherString) ? #"YES" : #"NO"));
This is the result:
0x35cc vs 0x35cc -> YES
So yes, the instance is the same although it was not intentional.
What I can imagine with these results is that the system allocates all the NSNumber objects instantiated with constant integers somewhere in the memory stack too.
But my question now is: why do they do that? Isn't the waste of memory more important than the time to generate the instances?
Then I thought: what about the floats? Floating point numbers can not really be compared with the equal operator because of the binary representation and all that stuff. And here is the last test:
float floatValue = 5.41553f;
NSNumber *aFloatNumber = [NSNumber numberWithFloat:floatValue];
NSNumber *anotherFloatNumber = [NSNumber numberWithFloat:floatValue];
NSLog(#"%p vs %p -> %#", aFloatNumber, anotherFloatNumber, ((aFloatNumber == anotherFloatNumber) ? #"YES" : #"NO"));
And here is the only expected result!
0x712f180 vs 0x74299a0 -> NO
What can you say about this? Do you really think this is the best behavior (and the more logic)?
Thanks for sharing your knowledge!
The use of the == operator with NSNumber only works in some cases because the NSNumber implementation internally uses a few global instances for the integers 0 through X (12 or 15 or something).
The memory to hold a dozen NSNumber objects in memory is trivial.
Regardless, never use the == operator to check equally. Always use isEqual: (or its variants). Never rely on implementation details or compiler optimizations like this.
Related
I am quite new to objective-c and I am trying to convert an int into a NSNumber so that I can save it into Core-Data.
I've the following piece of code (index is an NSInteger)
- (void) associateOrNotToARoutine:(NSString*)exerciseName associate:(BOOL)associate index:(NSInteger)index
NSLog(#"number w index %d, %d",[NSNumber numberWithInteger:index],index);
and it returns
number w index 170413600, 2
I need an int of 2 to be translated into a number 2 along with all other numbers to be translated into the correct number... Could anyone tell me why i am getting this convertion? I tried reading on NSNumber manual but i found nothing
Try:
NSLog(#"number w index %#, %d",[NSNumber numberWithInteger:index],index);
^^
The %# format specifier will call the [NSNumber description] method, which should return the value you are after. Your original code will return the address of the NSNumber object, not its content.
Even though this question has already been answered, I thought I'd flesh out a longer answer for future readers in general:
What's happening?
%d is a C format string used to indicate one of the passed parameters is an integer (int) ivar value. Much like %f is used for float values.
[NSNumber numberWithInteger:index] returns a pointer to an NSNumber instance. If you use %d, NSLog thinks you're passing it an integer when, in fact, you're passing a pointer. So the pointer value (a memory address) is printed.
What's %#?
As mentioned by trojanfoe: %# tells NSLog() that you are passing an object. In that case, NSLog asks the object to describe itself using a string… it calls the description method.
Specific answer
For this specific question, there are multiple ways. The two main one being:
NSLog(#"number w index %#, %d", [NSNumber numberWithInteger:index], index);
NSLog(#"number w index %d, %d", [[NSNumber numberWithInteger:index] intValue], index);
Extra goodness
When using %#, the passed object can be anything that responds to description, essentially any descendant of NSObject. Also, if you're creating your own classes, it's a good idea to overload description to return a more meaningful string than the default NSObject implementation.
// Try using it with NSArray or NSDictionary and see how each describe themselves.
NSLog(#"the array description: %#", myArray);
NSLog(#"the dictionary description: %#", myDictionary);
You should use,
[[NSNumber numberWithInteger:index] intValue]
to get the integer value, the NSNumber, is holding
I thought that I knew how to use fast enumeration, but there is something I don't understand about it. If I create three NSString objects and three NSNumber objects and put them in an NSMutableArray:
NSString *str1 = #"str1";
NSString *str2 = #"str2";
NSString *str3 = #"str3";
NSNumber *nb1 = [NSNumber numberWithInt:1];
NSNumber *nb2 = [NSNumber numberWithInt:2];
NSNumber *nb3 = [NSNumber numberWithInt:3];
NSArray *array = [[NSArray alloc] initWithObjects:str1, str2, str3, nb1, nb2, nb3, nil];
then I make do fast enumeration on all NSString objects, like this:
for (NSString *str in array) {
NSLog(#"str : %#", str);
}
In the console, I get this result :
2011-08-02 13:53:12.873 FastEnumeration[14172:b603] str : str1
2011-08-02 13:53:12.874 FastEnumeration[14172:b603] str : str2
2011-08-02 13:53:12.875 FastEnumeration[14172:b603] str : str3
2011-08-02 13:53:12.875 FastEnumeration[14172:b603] str : 1
2011-08-02 13:53:12.876 FastEnumeration[14172:b603] str : 2
2011-08-02 13:53:12.876 FastEnumeration[14172:b603] str : 3
I logged only the NSStrings, but I get a line for every object in the array, even the NSNumbers and I don't understand why. Does fast enumeration always use every object contained in an array?
When you write a forin loop like that, it casts every object in the array as an NSString, then prints them out as requested.
If you want only the NSStrings, you would need to write something like this:
for (id obj in array) {
if ([obj isKindOfClass:[NSString class]]) {
NSLog(#"str: %#", obj);
}
}
The for all loop doesn't know the difference between NSStrings and Integers -- it will simply go through the entire array, cast each as an NSString, and print them out as you asked.
I'm pretty sure that fast enumeration returns all objects in the array- all that you're doing in for (NSString *str in array) is typecasting str to an NSString. In the body of the loop you need to check the class of the returned object to make sure that it is an NSString.
for(NSString *str in array)
{
if([str isKindOfClass:[NSString class]])
NSLog(#"str : %#", str);
}
Objective-C is dynamically typed, meaning that at runtime (when the loop actually runs), objects are all effectively one type (id) with different classes. The language allows optional compile-time static typing, but all that does is check whether the messages you're sending are valid for the type you've marked. It doesn't actually change the behavior of your program. If you cast an object to be a different type than it actually is, all you're doing is lying to the compiler and defeating its type-checker.
Every object that descends from NSObject implements the method - (NSString)description, %# in Objective-C formate string will take the corresponding argument for the %# and call its description method, Most subclasses of NSObject will implement there own version of - (NSString)description. The same thing happens when you type
> po anObject
in the debugger.
for (NSString *str in array) {
is a way to enumerate through all the elements in array.
You expectative that by specifying NSString you get only the objects of that type is not correct. Rather, all the objects pointers are cast to that type (NSString*).
Have a look at Fast Enumeration in The Objective-C Programming Language guide.
I don't understand where is the unexpected behavior, using the enhanced for loop in an NSMutableArray will just iterate thru every single object in the array which in your case is 6, the result is correct and expected.
The numbers will just get casted to Strings.
in fast enumeration no typecasting,just assigning the pointer into new object
I love the shorthand handling of string literals in Objective C with the #"string" notation. Is there any way to get similar behavior with NSNumbers? I deal with numbers more and it's so tedious having [NSNumber numberWithWhatever:] calls everywhere. Even creating a macro would work, but my knowledge of how best to do that is limited.
Since nobody has mentioned this... If you need to wrap a value in an NSNumber, the NSNumber literal syntax is as follows.
int val = 13;
NSNumber *numVal = #(val);
As of Clang v3.1 you can now use Objective-C literals.
NSNumber *fortyTwo = #42; // equivalent to [NSNumber numberWithInt:42]
NSNumber *fortyTwoUnsigned = #42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
NSNumber *fortyTwoLong = #42L; // equivalent to [NSNumber numberWithLong:42L]
NSNumber *fortyTwoLongLong = #42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
So, answering your specific question:
[Tyler setArms:[[[NSNumber alloc] initWithInt:1] autorelease]];
Can now be written as:
[Tyler setArms:#1];
There are also literals for arrays and dictionaries, but they are beyond the scope of this question.
To take advantage of literals in Xcode you'll need at least version 4.4 -- this comes with Apple's LLVM 4.0 compiler.
I'm using a macro like
#define N(x) [NSNumber numberWithInt: x]
wich leads to code like
[N(123) intValue];
update:
One should be aware of the CPU and memory consumption of such a macro. While the #"…" strings are static compiler generated strings of the constant string class (depends on foundation maybe NSConstantString in Cocoa?) the macros create code which is evaluated at runtime and therefore create a new object every time they are called.
Xcode 4.4 has introduced the Clang features that rjstelling mentioned for literals for NSNumber, NSArray and NSDictionary. The syntax is simple:
//Number literal
NSNumber *pi = #3.14;
//Array literal
NSArray *primes = #[ #2, #3, #5, #7, #11 ]; //No nil terminator needed
//Dictionary literal
NSDictionary *dict = #{
#"key1": #42,
#"key2": #"Another key",
#3: #"A NSNumber key"
}; //No nil terminator, stored in "key:value," format
Some context: I'm trying to clean up some of my FMDB code. My one table has a lot of columns and the method in FMDB I need to use is one that expects a variable number of arguments, similar to NSString's class method +stringWithFormat:.
An example:
[db executeUpdate:#"insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)" ,
#"hi'", // look! I put in a ', and I'm not escaping it!
[NSString stringWithFormat:#"number %d", i],
[NSNumber numberWithInt:i],
[NSDate date],
[NSNumber numberWithFloat:2.2f]];
When a table only has 5 columns it's not that bad but when a column has 20+ it starts to get hairy.
What I'd like to do is create a dictionary with all db abstraction information and build these queries dynamically. My question is... How in Objective-C do I fake out that method expecting a variable number of arguments and instead perhaps hand it an NSArray?
Related info:
How can I write a method that takes a variable number of arguments, like NSString's +stringWithFormat:?
(Edit: This worked back in the GCC days. It doesn't under Clang as of Xcode 4.6.)
Get the objects in the array into a C array, then treat that as a varargs list:
//The example input array
int i = 42;
NSArray *array = [NSArray arrayWithObjects:
[NSString stringWithFormat:#"number %d", i],
[NSNumber numberWithInt:i],
[NSDate date],
[NSNumber numberWithFloat:2.2f],
nil];
//The example destination (using NSString so anyone can test this)
NSString *string = nil;
//The intermediary C array
NSObject **arrayObjects = malloc(sizeof(NSObject *) * [array count]);
if (arrayObjects) {
//Fill out the C array.
[array getObjects:arrayObjects];
//Use the C array as a va_list.
string = [[[NSString alloc] initWithFormat:#"%# %# %# %#" arguments:(va_list)arrayObjects] autorelease];
free(arrayObjects);
}
NSLog(#"string: %#", string);
Output:
2009-03-26 20:10:07.128 NSArray-varargs[606:10b] string: number 42 42 2009-03-26 20:10:07 -0700 2.2
In your case, you'll use the -[FMDatabase executeUpdate:arguments:] method.
It might be easier to just make a category on FMDatabase that takes an array and does the updates. You should be able to copy most of executeUpdate to do it.
I think NSInvocation may do what you're looking to do.
Just be careful when calling setArgumentForIndex because args 0 and 1 are implicit ones that Obj-C fills in, where arg 2 is the first "real" arg that you're passing.
This may not be the example you're looking for. But in this case I'd put your string values into an array and then use [theArray componentsJoinedByString:#","] to turn them into your sql argument list.
Now this must be easy, but how can sum two NSNumber? Is like:
[one floatValue] + [two floatValue]
or exist a better way?
There is not really a better way, but you really should not be doing this if you can avoid it. NSNumber exists as a wrapper to scalar numbers so you can store them in collections and pass them polymorphically with other NSObjects. They are not really used to store numbers in actual math. If you do math on them it is much slower than performing the operation on just the scalars, which is probably why there are no convenience methods for it.
For example:
NSNumber *sum = [NSNumber numberWithFloat:([one floatValue] + [two floatValue])];
Is blowing at a minimum 21 instructions on message dispatches, and however much code the methods take to unbox the and rebox the values (probably a few hundred) to do 1 instruction worth of math.
So if you need to store numbers in dicts use an NSNumber, if you need to pass something that might be a number or string into a function use an NSNumber, but if you just want to do math stick with scalar C types.
NSDecimalNumber (subclass of NSNumber) has all the goodies you are looking for:
– decimalNumberByAdding:
– decimalNumberBySubtracting:
– decimalNumberByMultiplyingBy:
– decimalNumberByDividingBy:
– decimalNumberByRaisingToPower:
...
If computing performance is of interest, then convert to C++ array std::vector or like.
Now I never use C-Arrays anymore; it is too easy to crash using a wrong index or pointer. And very tedious to pair every new [] with delete[].
You can use
NSNumber *sum = #([first integerValue] + [second integerValue]);
Edit:
As observed by ohho, this example is for adding up two NSNumber instances that hold integer values. If you want to add up two NSNumber's that hold floating-point values, you should do the following:
NSNumber *sum = #([first floatValue] + [second floatValue]);
The current top-voted answer is going to lead to hard-to-diagnose bugs and loss of precision due to the use of floats. If you're doing number operations on NSNumber values, you should convert to NSDecimalNumber first and perform operations with those objects instead.
From the documentation:
NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.
Therefore, you should convert your NSNumber instances to NSDecimalNumbers by way of [NSNumber decimalValue], perform whatever arithmetic you want to, then assign back to an NSNumber when you're done.
In Objective-C:
NSDecimalNumber *a = [NSDecimalNumber decimalNumberWithDecimal:one.decimalValue]
NSDecimalNumber *b = [NSDecimalNumber decimalNumberWithDecimal:two.decimalValue]
NSNumber *result = [a decimalNumberByAdding:b]
In Swift 3:
let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Why not use NSxEpression?
NSNumber *x = #(4.5), *y = #(-2);
NSExpression *ex = [NSExpression expressionWithFormat:#"(%# + %#)", x, y];
NSNumber *result = [ex expressionValueWithObject:nil context:nil];
NSLog(#"%#",result); // will print out "2.5"
You can also build an NSExpression that can be reused to evaluate with different arguments, like this:
NSExpression *expr = [NSExpression expressionWithFormat: #"(X+Y)"];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, #"X", y, #"Y", nil];
NSLog(#"%#", [expr expressionValueWithObject:parameters context:nil]);
For instance, we can loop evaluating the same parsed expression, each time with a different "Y" value:
for (float f=20; f<30; f+=2.0) {
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, #"X", #(f), #"Y", nil];
NSLog(#"%#", [expr expressionValueWithObject:parameters context:nil]);
}
In Swift you can get this functionality by using the Bolt_Swift library https://github.com/williamFalcon/Bolt_Swift.
Example:
var num1 = NSNumber(integer: 20)
var num2 = NSNumber(integer: 25)
print(num1+num2) //prints 45