Acquiring NSInteger Value - objective-c

I am trying to grab the value of an NSInteger and set a UILabel value to it. The code is as follows:
counter_.text = [NSString stringWithFormat:#"%#", [counterAmount intValue]];
where counter_ is my label and counterAmount is my NSInteger. I keep getting a "Receiver type 'NSInteger *' (aka 'int *') is not 'id' or interface pointer, consider casting it to id.
I'm not quite sure how to understand this. I appreciate of your help.

intValue is an NSNumber method that returns a C primitive value. %# prints objects. In order to output a C primitive value you have to supply the type in the formatting string. %d is the type for signed integer.
As per the question, and as pointed out to me quite correctly by borrden below, the type being dealt with here is NSInteger rather than NSNumber. In iOS NSInteger is a typedef of int, so you're dealing directly with a primitive type. The NS prefix does not mean that its an object.

Since counterAmount is a NSInteger, you can not use intValue on it (since it isn't an object, you can't send any messages to it, actually).
Instead, use:
counter_.text = [NSString stringWithFormat:#"%d", counterAmount];
Now that being said, if you are displaying this value to a user you should really be using a number formatter so that it is formatted the way that they have set it up to display in the settings app:
NSNumber *number = [NSNumber numberWithInt:counterAmount];
NSNumberFormatter *formatter = [NSNumberFormatter new];
formatter.numberStyle = NSNumberFormatterDecimalStyle; // Or whichever style is appropriate for your number.
counter_.text = [formatter stringFromNumber:number];

Related

arc4random in NSNumber giving negative values?

I'm creating a random number and storing it in a NSNumber object like this:
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(2^32-1)];
I also tried:
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(4294967295)];
NSNumber *index = #(arc4random_uniform(4294967295));
At some point I'm also assigning the number 1 like this:
NSNumber *index = #(1);
This should give me only positive numbers.
Later on, I print out these numbers like this:
NSString *string = [NSString stringWithFormat:#"%#", index];
This gives me some negative values for the random numbers and 1 is being printed as 1. So I though maybe if I do:
NSString *string = [NSString stringWithFormat:#"%u", index.unsignedIntValue];
I'll get only positive numbers - which I do - but now 1 is suddenly being printed as some large positive number, also.
What's going on here? How can I correctly store a u_int32 (which arc4random returns) in a NSNmber and make sure that they are only positive?
Use
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(exp2(32)-1)];
I never get any negative numbers. arc4random_uniform(x) always returns a number between 0 and x, and the stringvalue of the NSNumber generated from it is correct.
EDIT: replaced exp2(31) with exp2(32)
You said in a comment that the index is stored in a Core Data entity as an "Integer 32" attribute, and I assume that is where the problem comes from.
Core Data dynamically generates getter and setter methods for all attributes (and relationships) of managed object classes. These accessor methods are different from the "usual" #synthesized accessor methods which are backed up by an instance variable.
For an "Integer 32" attribute, Core Data uses a (signed) integer for the attribute, and when you set a value, it is just cast or truncated to int. Example:
e.index = [NSNumber numberWithUnsignedInt:0xFFFFFFF0U];
// This would give the same result:
// e.index = [NSNumber numberWithLongLong:0x1234FFFFFFF0LL];
NSNumber *val = e.index;
NSLog(#"value=%#, type=%s", val, [val objCType]);
// Output: value=-16, type=i
The output type=i shows that the value contains an int.
If you need unsigned integers in the range 0 .. 2^32-1, then you can either (as you already did) use unsignedIntValue:
unsigned x = [val unsignedIntValue];
or store the attribute as "Integer 64".
Remarks:
I am fairly sure that this is not a problem of arc4random_uniform.
In your first code example arc4random_uniform(2^32-1), you should note that ^ is exclusive-or, not exponentiation.

discussing functionality of id's stringValue function?

I got a NSMutableArray object with int values
and I can get a certain value via :
int *v0=[[[arrayObj objectAtIndex:0] intValue];
there is no problem.
But
I got a NSMutableArray object with NSString values
and I cannot get a certain value via :
NSString *v0=[[[arrayObj objectAtIndex:0] stringValue];
//raises error
I want to learn and understand exactly what stringValue for... and why this error occurs ?
NSString *v0=[arrayObj objectAtIndex:0];
works as expected.I asusme its some kind of pointer with null terminated so it can leech value.
Im not sure this line is also unicode/encoded string safe code.
in conclusion:
want to know the purpose of stringValue with some lines o code snippets
I got a NSMutableArray object with int values
That's not possible, Cocoa arrays always contain objects. You probably have an array of NSNumber objects that wrap the integers, like:
NSArray *arrayOfNumbers = #[#1, #2, #3];
NSNumber objects have an intValue method, so this works:
int value = [arrayOfNumbers[0] intValue];
On the other hand when you have an array of strings ...
NSArray *arrayOfStrings = #[#"1", #"2", #"3"];
... you want to access individual elements directly, without converting the string object to something else:
NSString *element = arrayOfStrings[0];
NSString objects do not understand the stringValue method:
[arrayOfStrings[0] stringValue]; // crash: does not recognize selector
Back at the beginning, our NSNumber objects from the first array do understand stringValue. You can use it to convert the number to a string:
NSString *intString = [arrayOfNumbers[0] stringValue];
To make the confusion perfect, NSString also understand the intValue message:
int value = [arrayOfStrings[0] intValue];
Here intValue means to try to convert the string to a plain C int value.
The error you will be getting (but failing to post with your question) will be Unknown selector sent to instance and this is because NSString doesn't have a stringValue method.
The approach you suggest is correct:
NSString *v0 = [arrayObj objectAtIndex:0];
EDIT (prompted by #Answerbot's answer):
The reason you are confused is that [NSString intValue] is used to convert the string value to an integer, as long as the string represents an integer (i.e. #"123"). However you don't need this for string as the object is already a string. It's therefore not provided.

KVC - about data type

this is the code:
NSNumber *taskId = [[self.taskList objectAtIndex:indexPath.row] valueForKey:#"identity"];
NSInteger *intTaskId = [[self.taskList objectAtIndex:indexPath.row] valueForKey:#"identity"];
self.taskList is an NSArray which filled with core data fetch request in ViewController's viewDidLoad method.
the taskId is: 1
the intTaskId is: 269303816
In actually, the value stored in core data is: 1
below is my questions:
1, I am confused why the NSInteger incorrect?
2, Should I have to replace NSInteger with NSNumber to avoid any other problems?
NSNumber is an object, whereas NSInteger is simply a typedef for a primitive (non-object) type (like int). NSInteger is not a subclass of NSNumber. Core Data returns numbers as instances of NSNumber. You're getting the weird NSInteger value because it's pointing to an object of type NSNumber but attempting to print it as if it were just an integer.
You'll need to replace NSInteger with NSNumber to avoid any problems. You could also use the intValue method on NSNumber to get back an NSInteger:
NSNumber *objTaskId = [[self.taskList objectAtIndex:indexPath.row] valueForKey:#"identity"];
NSInteger *intTaskId = [objTaskId intValue];
You'll need to do this if you want to do comparisons (greater than, equal too, smaller than) or arithmetic (you can't add an NSNumber to another NSNumber or an NSNumber to a primitive type like an int or float).

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."

What's the real type? NSString or NSNumber

I have a NSDictionary that contains data converted from json data, like {"message_id":21}.
then I use NSNumber *message_id = [dictionary valueForKey:#"message_id"] to get the data.
but when I use this message_id,
Message *message = [NSEntityDescription ....
message.messageId = message_id;
I got the runtime error, assigning _NSCFString to NSNumber,
so I have to use NSNumberFormatter to do the conversion.
NSString *messageId = [dictionary valueForKey:#"message_id"];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterNoStyle];
message.messageId = [f numberFromString:messageId];
this code works.
but when I was debugging, I saw message_id of
NSNumber *message_id = [dictionary valueForKey:#"message_id"]
has a valid value, 21.
Can anyone see the problem here?
You are trying to save a NSString to a NSNumber. If you want it as an NSNumber you can do:
NSNumber *message_id = [NSNumber numberWithInt:[[dictionary valueForKey:#"message_id"] intValue]];
This should solve your problem.
What library are you using to do the conversion? {"message_id":21} means that an NSNumber with a value of 21 should be returned as an NSNumber, {"message_id":"21"} should return it as an NSString.
Using a number formatter is total overkill. Use the method "integerValue" which works just fine both with NSString* and with NSNumber* - you will get the integer 21, whether the object is NSString or NSNumber. The formatter code will obviously run into trouble if your object is an NSNumber and not an NSString.
So: message.messageId = [[NSNumber numberWithInteger:[messageId integerValue]];
I'd probably add a category to NSDictionary
(NSNumber*)nsIntegerNumberForKey:(NSString*)key
which handles the situations where the key is not present, or where the value is a null value or a dictionary or array, so you can use it everywhere you need an NSNumber with an integer value from a JSON document and have error checking everywhere.
Read here SAVING JSON TO CORE DATA and JSON official page
The JSON standard is quite clear about how to distinguish strings from
numbers– basically, strings are surrounded by quotes and numbers are
not. JSON web services however, are not always good about following this requirement. And even when they are, they are not always consistent from one record to another.
So if you have receive NSNumber where NSString is preferred, you must inspect and fix yourself