Creating NSNumber with a #define variable - ios

From my understanding of NSNumber, if you create NSNumber with a certain data type, you need to access the variable with that same data type. For example
NSNumber *myIntNumber = [NSNumber numberWithInt:1];
int myInt = [myIntNumber intValue];
NSNumber *myNSIntegerNumber = [NSNumber numberWithInteger:1];
NSInteger myInteger = [myIntNumber integerValue];
If a NSNumber is created using a #define variable:
#define MY_DEFINE 6
does that mean that I cannot do the following
NSNumber *myNSIntegerNumber = [NSNumber numberWithInteger:MY_DEFINE];
NSInteger myInteger = [myIntNumber integerValue];
because MY_DEFINE is not a NSInteger?
I know that the above code would work in a 32-bit app, but I am trying to make sure that it will work on a 64-bit app, which is much more picky about these things, as well. And of course, it never hurts to do things properly.
If I cannot do the above, should I try to define MY_DEFINE differently so that I could use it to create a NSNumber that can later be used to retrieve a NSInteger?

Your understanding of NSNumber is incorrect. You can create an NSNumber with any type it supports and you can then use any of the supported type accessors. The two do not need to the same.
// Perfectly valid
NSNumber *number = [NSNumber numberWithFloat:3.14];
int val = [number intValue]; // results in 3
Your use of the #define is perfectly valid. The pre-compiler simply translates your code to:
NSNumber *myNSIntegerNumber = [NSNumber numberWithInteger:6];
Remember, a #define is nothing more than simple copy and paste (at least in this type of simple form) done before the code is compiled.
You can even use modern syntax:
NSNumber *number = #MY_DEFINE;
which becomes:
NSNumber *number = #6;
BTW - why post this question? Why not just try it first?

Related

Convert NSNumber to long

I am trying to convert a NSNumber to long but I get this error:
[__NSSingleObjectArrayI intValue]: unrecognized selector sent to
instance
Here is my code:
NSNumber *dbversion = [settings valueForKey:#"Version"];
long dbver = [dbversion longValue];
What am I doing wrong here?
*settings is a NSArray and "Version" is the key for a long value.
You are caught in the Key-Value Coding trap.
In some cases the result of valueForKey is an array which the error message clearly states.
Don't Never use valueForKey(unless you know what KVC does and you need KVC), use key subscription.
And as settings is an array you might get the first item
NSNumber *dbversion = settings[0][#"Version"];
and int is not long
long dbver = [dbversion longValue];
However on a 64-bit machine I recommend to use NSInteger
NSInteger dbver = dbversion.integerValue;
//I think you are storing string from dictionary "settings" to NSNumber so it's showing error like you mention in question.
Please Try with solution. May this help you.
NSNumber *dbversion = [NSNumber numberWithLong:[[settings valueForKey:#"Version"] longLongValue]];
int dbver = [dbversion longValue];

What is the difference between #"1.5" and #(1.5) while setting the value in NSDictionary?

In iPhone project,
It was while I was while setting Value in dictionary,
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#(2.8) forKey:#"Why"];
AND,
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#"2.8" forKey:#"Why"];
My question is Why not #"2.5" and #(2.5) ?
You have two questions, it would be better to have a single question.
But as to the difference,#"2.5" is an NSString where #(2.5) is an NSNumber. There is a big difference between textual and numeric data.
As for why you need an NSNumber and not NSString is obvious: the kerning is a numeric value.
using the #() syntax you can box arbitrary C expressions. This makes it trivial to turn basic arithmetic calculations into NSNumber objects see below:
double x = 24.0;
NSNumber *result = #(x * .15);
NSLog(#"%.2f", [result doubleValue]);
You can also refer NSNumber object as #"" string but cant make calculations like above example. In your case both are acceptable but here calculation makes difference.
When you use
#"2.5" it's behave like a string
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#"2.8" forKey:#"Why"];;
NSString *a = [dictionary ValueforKey:#"Why"];
but when you use #(2.8) then it's behave like a NSNumber
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#(2.8) forKey:#"Why"];;
NSNumber *a = [dictionary ValueforKey:#"Why"];
#(2.8) is a type of NSNumber.
#"2.8" is a type of NSString.
Both the type and value were different between there two.

Getting a warning in XCode about an NSMutableDictionary key that should be NSNumber

So I have the following in an Xcode 6.3 project where I have _menuHeaderPositions which should hold a keys of a menuHeaderID and an NSNumber which represents the contentOffset:
// _menuHeaderPositions is a NSMutableDictionary
// should be a NSNumber created from an NSUInteger
[_menuHeaderPositions setObject:[NSNumber numberWithFloat:_runningYPosition] forKey:[NSNumber numberWithInteger:menuHeader.menuHeaderID]];
// so unsigned long because of complaints about int
firstButton.tag=(unsigned long)menuHeaderID;
... later firstButton -> thisTap.view
// Works Fine
NSLog(#"you tapped me %lu", [_menuHeaderPositions objectForKey:[NSNumber numberWithInteger: thisTap.view.tag]]);
// THIS IS THE ISSUE
// Implicit Conversion loses integer precision: 'NSInteger' (aka long) to 'int'
NSNumber *pos=[_menuHeaderPositions objectForKey:[NSNumber numberWithInt:thisTap.view.tag]];
But I get this error and am pretty clueless as to what is going on here:
Implicit Conversion loses integer precision: 'NSInteger' (aka long) to 'int'
I can access the correct value later as [pos floatValue] but how do I get this warning to go away?
edit 1
trying this didn't seem to work:
NSNumber *pos=[_menuHeaderPositions objectForKey:[NSNumber numberWithInt:#(thisTap.view.tag)]];
The tag property has a type of NSInteger. You are attempting to pass this NSInteger to a method (numberWithInt:) that expects an int.
You have two choices:
Use NSNumber numberWithInteger:
NSNumber *pos=[_menuHeaderPositions objectForKey:[NSNumber numberWithInteger:thisTap.view.tag]];
Use modern boxing: #(thisTap.view.tag)
NSNumber *pos=[_menuHeaderPositions objectForKey:#(thisTap.view.tag)];
You can also use modern dictionary syntax and the line simply becomes:
NSNumber *pos = _menuHeaderPositions[#(thisTap.view.tag)];
First you should clear the data type of your menuHeader.menuHeaderID, which has two identity —— the key of the dictionary and the tag of the view.
As #rmaddy said, the tag property of the UIButton has type of NSInteger, which is NOT simply int.
This is the doc of numberWithInt: and numberWithInteger:.
Briefly speaking, use numberWithInteger: rather than numberWithInt:.
firstButton.tag = (NSInteger)menuHeaderID;
NSNumber *pos = [_menuHeaderPositions objectForKey:[NSNumber numberWithInteger:thisTap.view.tag]];

Why aren't these NSString instance variables allocated?

first post here. I was reading through an Objective-C tutorial earlier, and I saw that they had made a couple of NSString instance variables like this:
#implementation MyViewController {
NSString *stringOne;
NSString *stringTwo;
NSString *stringThree;
NSString *stringFour;
NSString *stringFive;
}
And then simply used them in ViewDidLoad like this:
- (void)viewDidLoad
{
[super viewDidLoad];
stringOne = #"Hello.";
stringTwo = #"Goodbye.";
stringThree = #"Can't think of anything else to say.";
stringFour = #"Help...";
stringFive = #"Pheww, done.";
}
How have they done this without instantiating the string? Why does this work? Surely you'd have to do something like stringOne = [NSString stringFromString:#"Hello."]; to properly alloc and init the object before you could simply do stringOne= #"Hello.";.
Sorry if this a dumb question, but I find these little things throw me.
Thanks,
Mike
From the Apple String Programming Guide:
Creating Strings
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"Contrafibularity";
Note that, when creating a string constant in this fashion, you should use UTF-8 characters. Such an object is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated. You can also send messages directly to a string constant as you do any other string:
BOOL same = [#"comparison" isEqualToString:myString];
String constants like #"Hello" are already allocated and initialized for you by the compiler.
Just remember this basic thing:-
NSString *string = ...
This is a pointer to an object, "not an object"!
Therefore, the statement: NSString *string = #"Hello"; assigns the address of #"Hello" object to the pointer string.
#"Hello" is interpreted as a constant string by the compiler and the compiler itself allocates the memory for it.
Similarly, the statement
NSObject *myObject = somethingElse;
assigns the address of somethingElse to pointer myObject, and that somethingElse should already be allocated and initialised.
Therefore, the statement: NSObject *myObject = [[NSObject alloc] init]; allocates and initializes a NSObject object at a particular memory location and assigns its address to myObject.
Hence, myObject contains address of an object in memory, for ex: 0x4324234.
Just see that we are not writing "Hello" but #"Hello", this # symbol before the string literal tells the compiler that this is an object and it returns the address.
I hope this would answer your question and clear your doubts. :)
actually this can be said "syntactic sugar". there are some other type of NS object that can be creatable without allocation or formatting.
e.g:
NSNumber *intNumber1 = #42;
NSNumber *intNumber2 = [NSNumber numberWithInt:42];
NSNumber *doubleNumber1 = #3.1415926;
NSNumber *doubleNumber2 = [NSNumber numberWithDouble:3.1415926];
NSNumber *charNumber1 = #'A';
NSNumber *charNumber2 = [NSNumber numberWithChar:'A'];
NSNumber *boolNumber1 = #YES;
NSNumber *boolNumber2 = [NSNumber numberWithBool:YES];
NSNumber *unsignedIntNumber1 = #256u;
NSNumber *unsignedIntNumber2 = [NSNumber numberWithUnsignedInt:256u];
NSNumber *floatNumber1 = #2.718f;
NSNumber *floatNumber2 = [NSNumber numberWithFloat:2.718f];
// an array with string and number literals
NSArray *array1 = #[#"foo", #42, #"bar", #3.14];
// and the old way
NSArray *array2 = [NSArray arrayWithObjects:#"foo",
[NSNumber numberWithInt:42],
#"bar",
[NSNumber numberWithDouble:3.14],
nil];
// a dictionary literal
NSDictionary *dictionary1 = #{ #1: #"red", #2: #"green", #3: #"blue" };
// old style
NSDictionary *dictionary2 = [NSDictionary dictionaryWithObjectsAndKeys:#"red", #1,
#"green", #2,
#"blue", #3,
nil];
for more information, see "Something wonderful: new Objective-C literal syntax".

Converting float to NSNumber

I am missing something basic, here. Must have forgotten it. But basically, I have the following code the purpose take an NSNumber, convert it to float, multiply it by 2 and return the result to an NSNumber. I get an error on the last step, and am stumped. What should I do there.
NSNumber *testNSNumber = [[[NSNumber alloc] initWithFloat:200.0f] autorelease];
float myfloatvalue = [testNSNumber floatValue] * -2;
NSLog(#" Test float value %1.2f \n\n",myfloatvalue);
[testNSNumber floatValue:myfloatvalue]; // error here is floatValue is not found
The method floatValue of NSNumber does not take parameters. If you would like to set a new float number, you need to re-assign testNSNumber, because NSNumber does not have a mutable counterpart:
testNSNumber = #(myfloatvalue); // The new syntax
or
testNSNumber = [NSNumber numberWithFloat: myfloatvalue]; // The old syntax
Swift 3.0:
let testNSNumber: NSNumber = NSNumber(value: myfloatvalue)
Swift 2.0 version:
let testNSNumber: NSNumber = NSNumber(float: myfloatvalue)

Resources