is NSDictionary non-ordered completely - objective-c

As we know,NSDictionary is non-ordered.however,when keys is number,when the dictionary is printed,they are printed by ascending number. i have try many times.

the order of a dictionary depends on the value that is returned by the hash method of the added key-object. it is very like, that NSNumber returns its value, it is was created with an Integer. in that case your observation would be correct.
more infos: http://bynomial.com/blog/?p=73
try ing this code
NSArray *numbers = #[#0,#1,#2,#3];
for (NSNumber *n in numbers) {
NSLog(#"%ld:%#", (unsigned long)[n hash], n);
}
it produces this output
0:0
2654435761:1
5308871522:2
7963307283:3
seems as if Knuth's hash algorithm was implemented half.
The original is
hash(i)=i*2654435761 mod 2^32
here it seems to be just
hash(i)=i*2654435761

Related

indexOfObjectIdenticalTo: - Getting junk value

NSString *yes0 = #"yes";
NSString *yes1 = #"YES";
NSString *yes2 = #"Yes";
NSString *yes3 = [NSString stringWithFormat:#"%#",yes1];
NSArray *yesArray = [NSArray arrayWithObjects:#"yes", #"YES", #"Yes", #"YES", nil];
NSArray *yesArray1 = [NSArray arrayWithObjects:yes0, yes1, yes2, yes3, nil];
NSUInteger index;
index = [yesArray indexOfObjectIdenticalTo:yes3];
NSLog(#"\nindex : %d", index); // 1st Output
index = [yesArray1 indexOfObjectIdenticalTo:yes3];
NSLog(#"\nindex : %d", index); // 2nd Output
1st Output
Output i receive is: "2013-07-18 16:42:04.896 Collections - Arrays[2778:f803] index : 2147483647"
2nd Output
Output i receive is: "2013-07-18 16:42:04.896 Collections - Arrays[2778:f803] index : 3"
I get confused due to the outputs i receive. Kindly explain me the process why i get the junk value during the output 1. According me, both arrays are identical with objects. Then why this junk value.
Also having a question:
According to apple, indexOfObjectIdenticalTo: returns - The lowest
index whose corresponding array value is identical to anObject.
Upto my understanding, in yesArray1 - yes1 is same as yes3. My expecting value of output 2 is 1 which gets contradict with the actual printed value (3). Also please let me understand it properly why it is printing 3 rather than 1.
First off, it's not a "junk value", it's the NSNotFound constant.
The first index is not found because yes3 is not in yesArray (it's only in yesArray1) – note that indexOfObjectIdenticalTo: checks for pointer identity, not object equality (unlike indexOfObject:).
indexOfObjectIdenticalTo checks for pointer equality, not object equality. 2147483647 isn't a junk value, it's the value of NSNotFound (which is the defined result if no index is found).
indexOfObjectIdenticalTo : checks for pointer equality
indexOfObject: checks Object equality.
Good Luck !!!

NSNumber returning different value than the original int

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

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.

Getting C-style array from objects of NSArray

I have an NSArray arr. It has a bunch of NSNumber objects. I'm trying to calculate statistics analysis on the array using GNU's GSL. GSL takes parameters as C-style arrays.
Is there any mechanism that can, for example, run 'intValue' on all of the objects in a NSArray object, and convert the results that to a C-style array?
I don't really want to copy the contents of the NSArray to a C-style array, as it's a waste of space and cycles, so I'm looking for an alternative.
The mechanism you're describing — run intValue on all the objects in the NSArray and give a C-style array — seems to be exactly the same thing you describe as "a waste of space and cycles." It's also the only real way to do this if you need a C-style array of ints. Best approach I can think of:
int *c_array = malloc(sizeof(int) * [yourArray count]);
[yourArray enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id number, NSUInteger index, BOOL *unused) {
c_array[index] = [number intValue];
}];
Try this:
id *numArray = calloc(sizeof(id), yourArray.count);
[yourArray getObjects: numArray range: NSMakeRange(0, yourArray.count)];
That gives you a C-array of NSNumbers. An alternative that gives you ints:
int *numArray = calloc(sizeof(int), yourArray.count);
for (int i = 0; i< yourArray.count; i++)
numArray[i] = [[yourArray objectAtIndex: i] intValue];
There is no way to tell yourArray to return a C-array of ints directly. NSArray has no concept of the contents it has, except that they are ids, and must be retained and released at the right times. It can at most return a C-array of ids, as in my first example.
You could probably write your own simple array class that contains ints (or floats or doubles, etc.) directly, in an internal C array, but there is no stock class for this.

need help converting an MPMediaItemPropertyPersistentID to a string and back again

I'm getting the ID of a media item from the MPMediaPickerController. According to the documentation, this value is an NSNumber object containing a uint64_t (unsigned long long). I would like to convert it to an NSString for saving in my data model. However, when I convert it to a string its value changes, and when I convert it back to a number it changes again! Obviously I'm not understanding something about these data types. Can you help?
MPMediaItem *mediaPicked;
// set mediaPicked to an MPMedia item using MPMediaPickerController...
NSLog(#"id as number: %qu", [mediaPicked valueForProperty:MPMediaItemPropertyPersistentID]); // outputs 566042331449280
NSLog(#"id as string: %#", [[mediaPicked valueForProperty:MPMediaItemPropertyPersistentID] stringValue]); // outputs 16204893883745507648
NSLog(#"id as number: %qu", [[[mediaPicked valueForProperty:MPMediaItemPropertyPersistentID] stringValue] longLongValue]); // outputs 9223372036854775807
If I try to play the media item before this conversion, it always works. But if I try to play the media item after this conversion, only about half of the media items I've tried work. So some ID values survive the conversion and some don't.
You are starting by saying this:
NSLog(#"id as number: %qu", [mediaPicked valueForProperty:MPMediaItemPropertyPersistentID]); // outputs 566042331449280
But that's wrong. %qu means "this thing is an unsigned long long". But this thing is not an unsigned long long. It's an object! It's an NSNumber wrapped around an unsigned long long. You are lying to NSLog, so you're getting garbage output in your very first statement.
Now, try this on your own machine:
uint64_t x = 16204893883745507648ULL;
NSLog(#"%qu", x);
NSNumber* n = [NSNumber numberWithUnsignedLongLong:x];
NSLog(#"%#", n);
NSLog(#"%#", [n stringValue]);
All of those NSLog statements give the same result - because they are all correct formulations, unlike the one you started with. So, those NSLog statements show you the kind of thing you ought to be saying.
Now, you might think: Oh, great, so I can get from an NSNumber to an NSString with stringValue after all. Yes, but you can't get back again. We cannot get from [n stringValue] to a correct NSNumber by using longlongValue, because a long long is not an unsigned long long. There is no unsignedLonglongValue. So you can't get there from here.
So what's the right thing to do? Don't convert at all! You've got an NSNumber, it's valid, just keep it and use it. An NSNumber is a value you can store in your model. (For example, it can go into a dictionary as a value or as a key, it can be a value in user defaults, and so on.)