如何在NSMutableArray中交换值?

9
这段代码给我造成了段错误,你有什么想法吗?allButtons是一个NSMutableArray,它包含3个对象,a=0,b=1,a和b都是int类型。
 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];
 }

编辑:

 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];
 }

如果可能的话,实际的错误信息可能会有所帮助。如果可以的话,发布类声明也可能有所帮助,以便我们可以看到所有按钮是否是一个属性,如果是,则其内存管理语义是什么等。 - jlehr
5个回答

22
第一次调用replaceObjectAtIndex:将释放旧对象(tempA),但这不应该导致段错误。正如@Zoran所提到的,尝试记录tempAretainCount并验证其计数。
另外,在数组中交换元素时,应使用exchangeObjectAtIndex:withObjectAtIndex而不是replaceObjectAtIndex:withObject。它从iPhone 2.0开始支持。

我尝试使用exchangeObjectAtIndex:withObjectAtIndex,但是出现了以下错误:Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[_PFArray exchangeObjectAtIndex:withObjectAtIndex:]: unrecognized selector sent to instance 0x3a35a30'。顺便说一下,recountCount返回了3。 - Thang Pham
你正在使用哪个版本的iPhone SDK?另外,请发布您正在创建NSMutableArray以及使用exchangeObject..的代码。 - Anurag
看起来 _PFArrayNSArray 的子类,没有 NSMutableArray 的方法。你可能需要创建一个新的对象,类型为 NSMutableArray 并用现有的数组进行初始化。NSMutableArray *theObject = [NSMutableArray arrayWithArray:allButtons] 然后在 theObject 上调用 exchangeObjectAt..。(http://webcache.googleusercontent.com/search?q=cache:i12_AOCFOTAJ:ericasadun.com/iPhoneDocs300/___p_f_array_8h-source.html+/search%3Fhl%3Den%26q%3D%2Bsite:ericasadun.com%2B_PFArray&cd=1&hl=en&ct=clnk&gl=us) - Anurag
这也解释了为什么之前replaceObjectAtIndex会导致段错误。 - Anurag
那真的解决了问题,我该如何将其存回到“allButtons”中? - Thang Pham

11

只是因为你说过

NSMutableArray *allbuttons = // something

这并不意味着它一定是一个NSMutableArray,它只是意味着编译器认为它将会是一个NSMutableArray。

如果它来自CoreData,那么它可能只是一个NSArray,因此您尝试的方法调用将无法正常工作 - 您将收到未识别的选择器或类似的错误提示。

您需要先将其转换为可变数组。

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];

1
或者只需使用NSMutableArray *allButtons = [coreData mutablecopy]; - Kaveh Vejdani

2

tempA 在第一次调用 replaceObjectAtIndex 时将被释放。在调用此方法时请记住这一点...我不知道为什么释放 tempA 会导致段错误,请检查它的 dealloc 是否正确。

检查 tempA 的保留计数以验证它确实被调用 replaceObjectAtIndex 销毁(而非简单地释放),如下所示:

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

如果您在这个级别看到保留计数为1,那么您的对象tempA正在被调用replaceObjectAtIndex释放。

recountCount 返回 3。 - Thang Pham
你是从主线程还是从次要线程调用这个函数?如果你是从次要线程调用它,你是否创建了自动释放池? - Zoran Simic

0
请仔细阅读并理解对象所有权的Cocoa规则。请注意,您尚未声明对tempA和tempB引用的对象的所有权,因此必须遵守以下规定:

通常情况下,接收到的对象在接收方法内部保持有效...(但如果您修改了从中接收另一个对象的对象,则还需小心)。该方法也可以安全地将对象返回给其调用者。

基本上,这行代码:

[allButtons replaceObjectAtIndex:a withObject:tempB];

可能会导致tempA被释放。这意味着后续的代码将导致allButtons向一个无效的对象发送保留消息,从而导致段错误。为了解决这个问题,在交换之前需要保留tempA,然后在交换后释放它或自动释放它。

注意,最好忘记保留计数。除非您完全了解所有涉及您对象的对象的实现,否则不能对对象的保留计数做出任何假设。例如,没有规定NSMutableArray的实现只会保留其元素一次。


0
使用此方法传递适当的索引。
exchangeObjectAtIndex:withObjectAtIndex: 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接