KVC - about data type - objective-c

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

Related

NSInteger not equal to long?

I am trying to parse some json data in Cocoa and I am having troubles with the NSInteger data type. The json string has some long values that I assign to NSInteger properties. Unfortunately the assigned NSInteger value differs completely from the long value. Why is that so? NSInteger is defined as typedef long NSInteger. I could have assigned the long value to a long property but I just would like to know why I can't assign it to an NSInteger.
-(void)parseData:(NSData*)data
{
NSError*err=nil;
NSDictionary*jsonData=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
_userID=(NSInteger)[jsonData valueForKeyWithoutNSNull:#"id"];
}
The _userID is a NSInteger.
The value retrieved from the dictionary is a long.
You can't simply cast an NSNumber (or even NSString) to an NSInteger. Dictionaries and other collection classes can't store primitive types like NSInteger.
Assuming your dictionary contains numbers and not strings then you need:
NSNumber *number = [jsonData valueForKeyWithoutNSNull:#"id"];
_userID = [number integerValue];

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.

Acquiring NSInteger Value

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];

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

how to operate on NSNumber in NSNArray created by NSString

i've got some method.
....{
NSString *mean = #"1:1:1:1:1:1:1:1:1";
tab = [self moveSourceArrayToDestinationArray:mean];
....}
-(NSArray*)moveSourceArrayToDestinationArray:(NSString*)sourceArray{
NSArray *destinationArray = [sourceArray componentsSeparatedByString:#":"];
for (NSNumber *number in destinationArray) {
sum += [number doubleValue];
}
NSLog(#"%d", [destinationArray objectAtIndex:1] * 5); // invalid operands to binary expression ('id' and 'int')
return destinationArray;
}
how can i do something mathematic operation on numbers in NSArray?
Your reference to NSNumber in your code is a mistake, and you got lucky that your code didn't throw an unrecognized selector exception. Your destinationArray is an array of NSStrings, not NSNumbers. It just so happens that both NSString and NSNumber have doubleValue and intValue methods. So when you say [number doubleValue] in your loop, you actually end up calling [NSString doubleValue] which of course still returns the number you want. However, if you were to try to call [number shortValue], where shortValue is a selector that only exists in NSNumber and not NSString, your code would throw an exception and not work.
The moral of this answer is that you should remove any reference to NSNumber in your code, or actually convert the objects in destinationArray to NSNumbers. Otherwise, you risk running into more trouble.
The easiest thing to do is to retrieve a numeric value from the NSNumber object, something you already did in your code snippet earlier. For example, try:
NSLog(#"%d", [[destinationArray objectAtIndex:1] intValue] * 5);
See the full list of numeric access functions in the NSNumber documentation under the section titled "Accessing Numeric Values."
Your object at [destionationArray objectAtIndex:index] is likely to be a NSNumber as well. Therefore, you have to to [[destinationArray objectAtIndex:index] doubleValue]at this point, too.