#"" string type literals for NSNumber - objective-c

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

Related

Selector name for NSArray literal constructor, like #[]?

It's been a while since Clang added Objective-C literal syntax for NSDictionary, NSArray, NSNumber, and BOOL literals, like #[object1, object2,] or #{key : value}
I'm looking for the selector name associated with the array literal, #[].
I tried to find out using the following code for NSArray, but I didn't see a selector that seemed right.
unsigned int methodCount = 0;
Method * methods = class_copyMethodList([NSArray class], &methodCount);
NSMutableArray * nameOfSelector = [NSMutableArray new];
for (int i = 0 ; i < methodCount; i++) {
[nameOfSelector addObject:NSStringFromSelector(method_getName(methods[i]))];
}
#[] is not a method on NSArray, so you're not going to find it there.
The compiler just translates #[] into a call to [NSArray arrayWithObjects:count:]. As in it basically finds all the #[] and replaces it with [NSArray arrayWithObjects:count:] (carrying across the arguments of course)
See the Literals section here
#[] uses +arrayWithObjects:count:
Official Clang Documentation
Array literal expressions expand to calls to +[NSArray arrayWithObjects:count:], which validates that all objects are non-nil. The variadic form, +[NSArray arrayWithObjects:] uses nil as an argument list terminator, which can lead to malformed array objects.
When you write this:
NSArray *array = #[ first, second, third ];
It expands to this:
id objects[] = { first, second, third };
NSArray *array = [NSArray arrayWithObjects:objects count:(sizeof(objects) / sizeof(id))];

Comparing pointers of NSNumber objects instantiated with const integers

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.

Is it possible to cast an NSInteger to NSNumber?

Is it possible to cast a NSInteger to a NSNumber object?
I need to convert the tag of a UIImageView object to a NSNumber object because I need to pass it as an argument to a function.
You cannot cast it because NSInteger is not an object, just an alias for a built-in type. You can always create a new NSNumber object from NSInteger, like this:
NSNumber *myNum = #(myNsIntValue);
or in the prior version of the compiler, use
NSNumber *myNum = [NSNumber numberWithInteger:myNsIntValue];
since Apple LLVM Compiler 4.0, there is an easier way to create NSNumber object:
NSNumber *x = #1234;
NSNumber *y = #(anIntegerVariable);
This is the more correct answer and it will not produce unexpected error.
NSNumber *myNum = [NSNumber numberWithInteger:myNsIntValue];
Because the doc said:
"numberWithInteger:
Creates and returns an NSNumber object containing a given value, treating it as an NSInteger."
"numberWithInt:
Creates and returns an NSNumber object containing a given value, treating it as a signed int."

Is there any way to pass an NSArray to a method that expects a variable number of arguments, such as +stringWithFormat:

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.

How to add two NSNumber objects?

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