NSArray NSDictionary preserve addobject order - cocoa

Is the addObject method of NSArray guaranteed to preserve order? So if I add one object1 and then object2 and then print them, will they always be in order? Is this also true for NSDictionary allValues array?

Arrays have guaranteed order, dictionaries do not. Neither do sets.

Related

Sorting NsMutable Array

I am getting floor names and storing in _floorNames (NSMutableArray) by using
_floorNames=[conferenceHall floorDetails:office];
NSLog(#"floor names=%#",_floorNames);
This will print floor names like this.
GROUND,
THIRD,
FIRST,
SECOND
Now i want to sort that floor names NsMutableArray as
GROUND,
FIRST,
SECOND,
THIRD
I have used
NSSortDescriptor *aa=[[NSSortDescriptor alloc]initWithKey:floor ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *descriptors = [NSArray arrayWithObjects:aa, nil];
a = [array sortedArrayUsingDescriptors:descriptors];
But it will crash my application.
Any suggestions ...
Try this,
NSArray *arrFloorNames=[[NSArray alloc]initWithObjects:#"GROUND",#"THIRD",#"FIRST",#"SECOND", nil];
arrFloorNames = [arrFloorNames sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSLog(#"%#",arrFloorNames);
What you want is you never get!!!
"GROUND, THIRD, FIRST, SECOND" to "GROUND, FIRST, SECOND ,THIRD" is what you want.
No algorithm can sort these strings based on their internal representation in numerals. This is something like, 0..1..2..3. You want to sort these integers written in English. Sorting can be done alphabetically so your result will be as First, Groung, Second, Third.
How to achieve?
You need to create an object of dictionary, with mapped value of Third to 3, second to 2, ground to 0. Then sort those numerical values. And then get Keys based on values(0,1,2etc).

NSDictionary sets values for NSMutableDictionary

I'm trying to make an rpg style game. I would like to know if and how to make an NSDictionary set the value for a mutable dictionary. The characters in my game will learn moves at different levels and the user can decide which move to use. If more info is needed let me now.
Here's an example
the NSDictionary pulls from a plist of attacks.
the attacks have names and power values.
the mutable array will set its attacks to the attacks in the NSDictionary.
You're looking for NSDictionary's - (NSArray *)objectsForKeys:(NSArray *)keys notFoundMarker:(id)anObject
Which
Returns the set of objects from the dictionary that corresponds to the specified keys as an NSArray.
Parameters keys An NSArray containing the keys for which to return corresponding values.
anObject The marker object to place in the corresponding element of the returned
array if an object isn’t found in the dictionary to correspond to a given key.
Discussion The objects in the returned array and the keys array have a one-for-one correspondence, so that the nth object in the returned array corresponds to the nth key in keys.
For example, you could run [dict objectsForKeys:[NSArray arrayWithObjects:str1, str2, nil] notFountMarker:[NSNull null]]; which will return the objects for the keys stored in str1, and str2. If the keys aren't found, the place holder will be an NSNull object.
If you're just after a mutable copy of a dictionary . . .
NSDictionary *atacks = /* Your dictionary of attacks */
NSMutableDictionary *mutable = [NSMutableDictionary dictionaryWithDictionary:attacks];

Sorting NSMutableArray with NSStrings in alphabetical order

I have a NSMutableArray with NSStrings and I want to sort them in alphabetical order, seems it's no hard, but I didn't find nice solution. Help me please.
Using sortUsingSelector: method with compare: as comparing selector:
NSMutableArray* strings = [NSMutableArray arrayWithObjects:#"dog", #"ant", #"cat",nil];
[strings sortUsingSelector:#selector(compare:)];
NSLog(#"%#", strings);

sorting an NSArray of NSDates

I have an NSArray of NSDate objects and I want to sort them so that today is at 0, yesterday at 1 etc.
Is it ascending or descending, and do i use a function, selector or what?
There are different sort methods for NSArray because there may be different ways you want to sort things. NSSortDescriptors are a general way that give you a lot of options as far as what keys to use in sorting, what selectors you want to use on those keys, and overall order to use, etc. Or you can use functions or comparator blocks instead if your case requires that or if that's more convenient for your particular case.
To answer your first question, if you want today to be first, followed by yesterday then, yes, that is of course descending order.
To sort some dates in descending order you can just do this: (assuming an NSArray full of NSDates called 'dateArray'):
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
NSArray *descriptors = [NSArray arrayWithObject: descriptor];
[descriptor release];
NSArray *reverseOrder = [dateArray sortedArrayUsingDescriptors:descriptors];
Or, if you are building for iOS 4+ or Snow Leopard+ you can do this:
NSArray *reverseOrderUsingComparator = [dateArray sortedArrayUsingComparator:
^(id obj1, id obj2) {
return [obj2 compare:obj1]; // note reversed comparison here
}];
Try this magic:
Sort array of dates in ascending order.
i.e. dates getting later and later, or to put it another way, dates going into the future.
NSArray ascendingDates = [dates sortedArrayUsingSelector:#selector(compare:)];
Sort array of dates in descending order. (what the question asked)
i.e. dates getting earlier and earlier, dates going into the past or to put it another way: today is at index 0, yesterday at index 1.
NSArray* descendingDates = [[[dates sortedArrayUsingSelector:#selector(compare:)] reverseObjectEnumerator] allObjects];

How do copy and mutableCopy apply to NSArray and NSMutableArray?

What is the difference between copy and mutableCopy when used on either an NSArray or an NSMutableArray?
This is my understanding; is it correct?
// ** NSArray **
NSArray *myArray_imu = [NSArray arrayWithObjects:#"abc", #"def", nil];
// No copy, increments retain count, result is immutable
NSArray *myArray_imuCopy = [myArray_imu copy];
// Copys object, result is mutable
NSArray *myArray_imuMuta = [myArray_imu mutableCopy];
// Both must be released later
// ** NSMutableArray **
NSMutableArray *myArray_mut = [NSMutableArray arrayWithObjects:#"A", #"B", nil];
// Copys object, result is immutable
NSMutableArray *myArray_mutCopy = [myArray_mut copy];
// Copys object, result is mutable
NSMutableArray *myArray_mutMuta = [myArray_mut mutableCopy];
// Both must be released later
copy and mutableCopy are defined in different protocols (NSCopying and NSMutableCopying, respectively), and NSArray conforms to both. mutableCopy is defined for NSArray (not just NSMutableArray) and allows you to make a mutable copy of an originally immutable array:
// create an immutable array
NSArray *arr = [NSArray arrayWithObjects: #"one", #"two", #"three", nil ];
// create a mutable copy, and mutate it
NSMutableArray *mut = [arr mutableCopy];
[mut removeObject: #"one"];
Summary:
you can depend on the result of mutableCopy to be mutable, regardless of the original type. In the case of arrays, the result should be an NSMutableArray.
you cannot depend on the result of copy to be mutable! copying an NSMutableArray may return an NSMutableArray, since that's the original class, but copying any arbitrary NSArray instance would not.
Edit: re-read your original code in light of Mark Bessey's answer. When you create a copy of your array, of course you can still modify the original regardless of what you do with the copy. copy vs mutableCopy affects whether the new array is mutable.
Edit 2: Fixed my (false) assumption that NSMutableArray -copy would return an NSMutableArray.
I think you must have misinterpreted how copy and mutableCopy work. In your first example, myArray_COPY is an immutable copy of myArray. Having made the copy, you can manipulate the contents of the original myArray, and not affect the contents of myArray_COPY.
In the second example, you create a mutable copy of myArray, which means that you can modify either copy of the array, without affecting the other.
If I change the first example to try to insert/remove objects from myArray_COPY, it fails, just as you'd expect.
Perhaps thinking about a typical use-case would help. It's often the case that you might write a method that takes an NSArray * parameter, and basically stores it for later use. You could do this this way:
- (void) doStuffLaterWith: (NSArray *) objects {
myObjects=[objects retain];
}
...but then you have the problem that the method can be called with an NSMutableArray as the argument. The code that created the array may manipulate it between when the doStuffLaterWith: method is called, and when you later need to use the value. In a multi-threaded app, the contents of the array could even be changed while you're iterating over it, which can cause some interesting bugs.
If you instead do this:
- (void) doStuffLaterWith: (NSArray *) objects {
myObjects=[objects copy];
}
..then the copy creates a snapshot of the contents of the array at the time the method is called.
The "copy" method returns the object created by implementing NSCopying protocols copyWithZone:
If you send NSString a copy message:
NSString* myString;
NSString* newString = [myString copy];
The return value will be an NSString (not mutable)
The mutableCopy method returns the object created by implementing NSMutableCopying protocol's mutableCopyWithZone:
By sending:
NSString* myString;
NSMutableString* newString = [myString mutableCopy];
The return value WILL be mutable.
In all cases, the object must implement the protocol, signifying it will create the new copy object and return it to you.
In the case of NSArray there is an extra level of complexity regarding shallow and deep copying.
A shallow copy of an NSArray will only copy the references to the objects of the original array and place them into the new array.
The result being that:
NSArray* myArray;
NSMutableArray* anotherArray = [myArray mutableCopy];
[[anotherArray objectAtIndex:0] doSomething];
Will also affect the object at index 0 in the original array.
A deep copy will actually copy the individual objects contained in the array. This done by sending each individual object the "copyWithZone:" message.
NSArray* myArray;
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:myArray
copyItems:YES];
Edited to remove my wrong assumption about mutable object copying
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray
copyItems:YES];
will create anotherArray which is a copy of oldArray to 2 levels deep. If an object of oldArray is an Array. Which is generally the case in most applications.
Well if we need a True Deep Copy we could use,
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject: oldArray]];
This would ensure that all levels are actually copied retaining the mutability of the original object at each level.
Robert Clarence D'Almeida,
Bangalore, India.
You're calling addObject and removeObjectAtIndex on the original array, rather than the new copy of it you've made. Calling copy vs mutableCopy only effects the mutability of the new copy of the object, not the original object.
To state it simply,
copy returns an immutable (can't be modified) copy of the array,
mutableCopy returns a mutable (can be modified) copy of the array.
Copy (in both cases) means that you get a new array "populated" with object references to the original array (i.e. the same (original) objects are referenced in the copies.
If you add new objects to the mutableCopy, then they are unique to the mutableCopy. If you remove objects from the mutableCopy, they are removed from the original array.
Think of the copy in both cases, as a snapshot in time of the original array at the time the copy was created.
Assume
NSArray *A = xxx; // A with three NSDictionary objects
NSMutableArray *B = [A mutableCopy];
B's content is NSDictionary object not NSMutableDictionary, is it right?
-(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it.
You have to know the return type of these copying stuff and while declaring the new object which one will be assigned the return value must be of immutable or mutable one, otherwise compiler will show you error.
The object which has been copied can not be modified using the new one,they are totally two different objects now.

Resources