2011-12-28 24 views
0

这里是我的代码简化:以一个对象了MutableArray的,并将其放置在一个新的对象

NSMutableArray* buildBlocks = [[[NSMutableArray alloc] initWithCapacity:0] retain]; 
Block* selectedBlock = [[[Block alloc] init] retain]; 

// Add several blocks to "buildBlocks" 

for(int i=0; i < [buildBlocks count]; i++) 
{ 
    Block* tempBlock = [buildBlocks objectAtIndex:i]; 

    if(tempBlock.selected) 
    { 
     // Move the block to the selected block 
     selectedBlock = tempBlock; 

     // Take the block out of the array 
     [buildBlocks removeObjectAtIndex:i]; 
    } 
} 

// Some code later 

if(selectedBlock.selected) // <---- Crashes here 
{ 
    // Do stuff 
} 

我要选择的块复制到“SelectedBlock,”删除块从数组中,然后再使用“SelectedBlock”。当我用这个代码,我总是得到“EXC_BAD_ACCESS我觉得在程序释放数据。‘SelectedBlock’它之前,我想我在做什么错

更新:?

感谢大家帮我解决它

+0

Xcode只是一个IDE。与这个问题无关。 – vikingosegundo 2011-12-28 22:57:19

+0

请注意,无条件前进('++ i'或'i ++')会导致您在删除任何对象时跳过对象。只有在不移除物体的情况下才会提前进行。 – 2011-12-28 23:14:41

回答

0

我想说,当你从阵列中移除它时,块会从你的下面释放出来,但是你已经在里面放入了虚假的(和不必要的)retains,所以很难告诉发生了什么事,却看不到你所遗漏的代码。

通常情况下,当我从数组中删除并反对并想要保留它时,我保留它。但是你仍然过度保留,所以可能不是问题,但没有看到其余的方法,我不能确定。

0

在这里你去:

NSMutableArray* buildBlocks = [[[NSMutableArray alloc] initWithCapacity:0] retain]; 
Block* selectedBlock; 

// Add several blocks to "buildBlocks" 

for(int i=0; i < [buildBlocks count]; i++) 
{ 
    Block* tempBlock = [buildBlocks objectAtIndex:i]; 

    if(tempBlock.selected) 
    { 
     // Move the block to the selected block 
     selectedBlock = tempBlock; 
     [selectedBlock retain]; // Retain selectedBlock here 

     // Take the block out of the array 
     [buildBlocks removeObjectAtIndex:i]; 
    } 
} 

// Some code later 

if(selectedBlock.selected) // <---- Crashes here 
{ 
    // Do stuff 
} 

[selectedBlock release]; // release when done. 

基本上,你保留一个全新的,从未使用过块在第2行selectedBlock从来没有得到保留,当你从数组中删除它,它被摧毁。因此,selectedBlock指向一个陈旧的旧内存导致崩溃。

+0

那么,为什么提问者的代码是错误的,为什么这个代码更好? (另外,如果数组为空,会发生什么情况?) – 2011-12-28 23:13:45

+0

通常您会看到'selectedBlock = [tempBlock retain];',但上面写成两行,只是为了清楚起见。 – amattn 2011-12-28 23:15:15

+0

理想情况下,您应该将selectedBlock初始化为零。 'Block * selectedBlock = nil;' – 2011-12-29 05:50:15

5
Block* selectedBlock = [[[Block alloc] init] retain]; 

这将创建(和不必要的保留,因为你已经拥有它)的新块。为什么你想要创建一个新的,当你的目标是检索一个你已经有的?

// Move the block to the selected block 
selectedBlock = tempBlock; 

这番话没有任何意义。没有什么东西从一个块移到另一个块;你正在设置selectedBlock变量指向你从数组中获得的块。在那之后,selectedBlocktempBlock都指向同一个块,它是数组中的块。

// Take the block out of the array 
[buildBlocks removeObjectAtIndex:i]; 

阵列拥有它所包含的所有块,所以当你删除您从数组,数组释放它得到了块。如果这是该块的唯一所有权,则该块因此被解除分配。之后的任何使用都是无效的。

如...

if(selectedBlock.selected) // <---- Crashes here 

selectedBlock点,你有,然后从块数组中删除。假设数组是唯一拥有它的数据,那么在这一点上它是一个死对象,所以是的,给它发送一条消息会导致崩溃。

您保留了初始化为selectedBlock的对象,但未保留稍后用该对象替换该对象的对象。保留该初始对象不会主动保留您分配给该变量的未来对象;它只保留了最初的对象。

有您需要更改几件事情:

  1. 初始化selectedBlocknil,不是指针到一个新的模块。

  2. 不要随意保留东西。始终保留一个目的。如果你不完全理解为什么保留某些东西是为了做什么(“让它不崩溃”本身并不是一个可以接受的理由),那么不要只是在它上面留下一个保留。了解the Advanced Memory Management Programming Guide中的内存管理规则,您将知道何时需要保留以及为什么您的retain不在[[[Block alloc] init] retain]中是不必要的。

  3. 当您保留某些内容时,请始终使用releaseautorelease消息将其与之平衡。你没有平衡的保留是泄漏,最终泄漏会导致问题。在iOS下,从用户的角度来看,它们会导致崩溃(更准确地说,您使用的内存太多,系统会杀死您的应用程序)。

  4. 当您将阵列中的对象分配到selectedBlock时,请保留它并自动释放它,然后再将其从阵列中移除。保留让你成为一个拥有者,autorelease使这个临时变为现实;作为一个所有者,只要持续这个时间,就会使对象活得足够长,以便你使用它,从而防止崩溃。

  5. 不要打扰询问所选块是否被选中。如果选择了块,则只指定一个块的指针selectedBlock,因此在您使用selectedBlock时,您已经知道它已被选中。结合上面的#1,您可以简单地测试selectedBlock是否为nil;如果它不是nil,则有一个选定的块,如果它是nil,则没有找到(即没有)选定的块。

  6. 当您得到此代码工作后,将其转换为ARC。 (在Edit/Refactor菜单中有一个菜单项。)然后,您不必保留或释放或自动释放任何东西;大多数事情都行得通。

相关问题