How to swap values in NSMutableArray?

This piece of codes segment fault on me, any idea why? allButtons is a NSMutableArray, it contains 3 objects, a=0, b=1, a and b are int type

 if(a != -1 && b!= -1){
    //Swap index in "allButtons"
    id tempA = [allButtons objectAtIndex:a];
    id tempB = [allButtons objectAtIndex:b];
    [allButtons replaceObjectAtIndex:a withObject:tempB]; //Seg fault here?????
    [allButtons replaceObjectAtIndex:b withObject:tempA];
    needLoad = false;
    [self setUpButtons];
 }

EDIT:

 NSMutableArray *allButtons = //fetch the array from Coredata. This work since I display the data onto the screen, plus, [allButtons count] return 3, and a=0, b=1
 f(a != -1 && b!= -1){
    //Swap index in "allButtons"
    [allButtons exchangeObjectAtIndex:a withObjectAtIndex:b];
    needLoad = false;
    [self setUpButtons];
 }

Answers


Just because you have said

NSMutableArray *allbuttons = // something

doesn't mean that it is definitely an NSMutableArray, it just means that the compiler thinks that it will be a NSMutableArray.

If it's from CoreData, it's probably just an NSArray so the method calls you are trying won't work - you'll get unrecongnised selector or something like that.

You will have to convert it to a mutable array first

NSArray *coreData = // core data call

// Create a mutable copy
// NB This means that you are now working on a copy, not the original :)
NSMutableArray *allButtons = [coreData mutableCopy];

The first call to replaceObjectAtIndex: will release the old object (tempA), but that shouldn't cause a seg fault. As @Zoran mentioned try logging the retainCount for tempA and verify its count.

Also for swapping elements in an array, you should use exchangeObjectAtIndex:withObjectAtIndex instead of replaceObjectAtIndex:withObject. It's supported from iPhone 2.0.


tempA is going to be released when you call the first replaceObjectAtIndex. Keep that in mind when calling this... I have no idea why releasing tempA would seg fault for you, examine what its dealloc does perhaps.

Check the retain count of tempA to verify that it is indeed dealloc-ed (not simply released) by the call to replaceObjectAtIndex like so:

id tempA = [allButtons objectAtIndex:a];
NSLog(@"retain count for tempA: %i", [tempA retainCount]);

If you see a retain count of 1 at this level, then your object tempA is being dealloc-ed by the call to replaceObjectAtIndex


Please read and understand the Cocoa rules on object ownership. Note that you have not claimed ownership over the objects referenced by tempA and tempB and you must therefore heed the following:

A received object is normally guaranteed to remain valid within the method it was received in ... (although you must also take care if you modify an object from which you received another object). That method may also safely return the object to its invoker.

Basically, the line:

[allButtons replaceObjectAtIndex:a withObject:tempB];

May cause tempA to be deallocated. This means that the subsequent line will cause allButtons to send a retain message to an invalid object, hence the seg fault. To fix the problem, you need to retain tempA before the swap and release it or autorelease it after.

NB it's wise to forget about retain counts. Unless you are fully aware of the implementation of all objects that touch your objects, you cannot make any assumptions about what the retain count of an object is. For instance, there's no rule that says that the implementation of NSMutableArray will only ever retain its elements once.


Use this method pass the appropritate index

exchangeObjectAtIndex:withObjectAtIndex: 

Need Your Help

Can a JavaScript function return itself?

javascript function self

Can I write a function that returns iteself?