views:

460

answers:

4

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];
 }
+2  A: 

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

Zoran Simic
`recountCount` return back 3.
Harry Pham
Are you calling this from the main thread or a secondary thread? If you're calling it from a secondary thread, did you create an auto-release pool?
Zoran Simic
+3  A: 

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.

Anurag
I try `exchangeObjectAtIndex:withObjectAtIndex` and this is what I got `Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[_PFArray exchangeObjectAtIndex:withObjectAtIndex:]: unrecognized selector sent to instance 0x3a35a30'`. BTW, `recountCount` return back 3.
Harry Pham
what version of the iPhone SDK are you using? Also, please post the code where you are creating the `NSMutableArray`, and using `exchangeObject..`
Anurag
I just edit my code. TYVM
Harry Pham
Anurag
that also explains why `replaceObjectAtIndex` was seg-faulting before.
Anurag
that actually fixed it, how do I store it back to `allButtons`?
Harry Pham
A: 

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.

JeremyP
+1  A: 

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 *temp = // core data call
NSMutableArray *allButtons = [NSMutableArray arrayWithArray:temp];
deanWombourne
ty that fix the problem.
Harry Pham