objective c arrays linked somehow - objective-c

Hi i have an array which i am trying to copy then remove an element from. The issue is i think i am removing the element from the copy but it also removes the element from the original array. I have no idea what is going on. Im new to objective c so any help would be much appreciated.
NSArray *newarray = appDelegate.orginalArray;
[newarray removeObjectAtIndex: 2];
When i look at the arrays after removing the object it had removed it from both newarray and orginalArray why would this be?
Many thanks

This isn't making a copy. Both newArray and appDelegate.originalArray refer to the same object. You would need to do this:
NSMutableArray *newArray = [appDelegate.originalArray mutableCopy];
Also note that I'm using NSMutableArray and mutableCopy to ensure the copy is mutable (i.e. supports adding and removing items)

Pointers, buddy, and mutable/immutable abstractions. newarray and appDelegate.originalArray are both pointers (references) to the same immutable (unchangeable) array. You want:
NSArray *newarray = [appDelegate.orginalArray mutableCopy];

Related

Objective C - NSMutableArray issue after sorting using sortedArrayUsingDescriptors

I have an NSMutableArray with custom objects.
I can addObjects, removeAllObjects and other operations with the array.
However, as soon as I sort the array via sortedArrayUsingDescriptors i cannot
perform any operations anymore such as removeallobjects. When debugging the code simply stops at this point.
Does anyone have an explanation ?
sortedArrayUsingDescriptors: returns a NSArray, not NSMutableArray.
you should use sortUsingDescriptors: to sort in place.
NSArray *sortedArray = [array sortedArrayUsingDescriptors:...];
vs.
[mutableArray sortUsingDescriptors:...];

Efficiency + safety: declare new NSArray var, or overwrite existing NSMutableArray with mutableCopy?

I need to sort a mutable array, but in this specific case when it comes time to sort, I don't need it to be mutable anymore. The sortedArrayUsingSelector: method returns an NSArray * even when called by an NSMutableArray * object. I have 3 options:
1) I can make a mutableCopy of the returned NSArray * and store it in the var I already have
NSMutableArray *mutableArray = [NSMutableArray array];
// add a bunch of stuff to the array
mutableArray = [[mutableArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] mutableCopy];
2) I can make a new NSArray * var to hold the returned NSArray *
NSMutableArray *mutableArray = [NSMutableArray array];
// add a bunch of stuff to the array
NSArray *array = [mutableArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
3) I can ignore Xcode's warnings and store the returned NSArray * object in an NSMutableArray * var
NSMutableArray *mutableArray = [NSMutableArray array];
// add a bunch of stuff to the array
mutableArray = [mutableArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
I realize that for most cases the difference is negligible, but considering available resources, efficiency, and safety, which would be the overall "best" option?
EDIT: I hadn't considered that the best option might be to create a non-mutable array from the mutable one before sorting it. Not sure if this would be, in fact, the best option, but something I figured I'd mention.
Since you have a mutable array already, just use the following method on NSMutableArray:
- (void)sortUsingSelector:(SEL)comparator
That way you're not recreating anything. This is likely more efficient than creating a new, sorted array from the original and then creating a mutable copy of that. Part of the point of having a mutable array in the first place is that you can change stuff around without needing to recreate it each time, so sorting is a very obvious thing to have here.
The array you get back from sortedArrayUsingSelector won't be a deep copy - it will contain the same pointers as the original array, just in a different order. These array methods in foundation will be well optimized, so I wouldn't worry about it too much.
Instead, just decide what you want. If you want a sorted NSArray * that won't look like an NSMutableArray *, just use sortedArrayUsingSelector, which returns an NSArray *
If you don't need the original unsorted array anymore, just sort the mutable array, like #Gavin suggests.

NSMutableArray Implementation

How is NSMutableArray implemented?
If there are a number of NSMutableArray references to a mutable array e.g. Source Array and each of these pointing arrays sort the objects differently, are the objects copied over into each array or are the object pointers just internally rearranged?
If the source array is updated with new objects, will the NSMutableArray pointers automatically add an the entry to their internal reference.
It just stores pointers.This means that if the NSMutableArray stores immutable objects, then you are sure that they'll not change their state, but if it has a mutable object the state of any referenced object may change at any time.
Exactly I don't know how it's implemented, but I would say a pointer to id.It allocates memory and then update the id at the index that needs:
id* pointers;
< Allocation>
pointers[i]= newObjectPointer;
It's a little hard to parse exactly the scenario you're asking about, but NS(Mutable)Array holds a list of object references. It does not copy the objects you add to it, just keeps a pointer. If those objects can change, and you change them from outside the array, that will be reflected in the things you read back from the array.
NSMutableArray * arr = [NSMutableArray array];
NSMutableArray * child = [NSMutableArray array];
[child addObject:#5];
[arr addObject:child];
[child addObject:#6];
NSLog(#"%#", arr[0]);
> [5, 6]

Need a memory management clarification wrt NSArray

Say I have:
NSDictionary *stuff; // {"1" => "hi", "2" => "bye"}
NSArray *array = [stuff allKeys];
allKeys makes a copy of stuff's keys, so array is now responsible for releasing this information.
Later on, when I want to
I cannot do:
array = [newStuff allKeys];
because it would just reassign the pointers and orphan the original array. I must first remove the objects
[array removeAllObjects];
Wanted to know if my understand is correct? Thanks!
Not quite.
NSArray *array = [stuff allKeys];
This gives you an array that you don't own. Whether it's technically a copy or not is not your problem. Since the accessor doesn't start with the word "alloc" or "new", or contain the word "copy", you don't own the return value, which means you don't need to release it. (But you do need to retain it if you want to keep it.)
If you later do this:
array = [newStuff allKeys];
that's fine. It stomps on the original reference, as you know, but since you don't own that reference anyways, it's OK to let it go. This new reference is also, of course, not yours unless you retain it.
No. allKeys returns an autoreleased NSArray. It will be released later unless you explicitly retain it. So setting array = [newStuff allKeys]; is perfectly fine. You should probably read this guide on Objective-C.

Merging NSArrays in Objective-C

I have an NSDictionary where each key points to an array. I later want to merge all of the values into one array. Is there a way to use the API to do something more efficient than say:
NSArray *anArray = [someDictionary allValues];
NSMutableArray *newArray = [NSMutableArray array];
start outter loop on anArray
start inner loop on objects in anArray
add objectAtIndex to newArray
Just use [newArray addObjectsFromArray:anArray];
-[NSMutableArray addObjectsFromArray:]
There is some confusion in Benn Gottlieb's answer above. To clarify, he is suggesting using addObjectsFromArray instead of the inner loop, whereas Coocoo is confused because he thinks it is being suggested as a replacement for ALL the looping. (If you do this, you will indeed be left with an unflattened array of arrays as per his objection.)
Here is a reasonably elegant solution that doesn't require any explicit looping:
NSArray *anArray = [someDictionary allValues];
NSArray *flattenedArray = [anArray valueForKeyPath: #"#unionOfArrays.self"];
btw this code will leave duplicates in the flattened array. If you want to remove duplicates, use distinctUnionOfArrays instead of unionOfArrays.