从MutableArray中取出一个对象并将其放在一个新对象中

时间:2011-12-28 22:48:55

标签: iphone objective-c cocoa-touch

这是我的代码简化:

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“中的数据。我做错了什么?

更新

感谢大家的帮助。我修好了。

3 个答案:

答案 0 :(得分:5)

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

这会创建(并且不必要地保留,因为您已经拥有它)一个新的Block。当你的目标是找回你已经拥有的那个时,你为什么要创建一个新的?

// 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. selectedBlock初始化为nil,而不是指向新版块的指针。

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

  3. 当您保留某些内容时,请始终使用autoreleaseselectedBlock消息进行平衡。保持不平衡是泄漏,泄漏最终会导致问题。在iOS下,从用户的角度来看,它们会导致崩溃(更准确地说,您使用了太多内存而系统会杀死您的应用)。

  4. 当您将数组中的对象分配给selectedBlock时,保留它并在从阵列中删除它之前自动释放它。保留使您成为所有者,自动释放使其成为临时的;作为拥有者,只要持续时间,将使对象保持足够长的时间以便您使用它,防止崩溃。

  5. 不要问所选的块是否已被选中。如果选择了selectedBlock,则只指定一个块的指针,因此当您使用selectedBlock时,您已经知道它已被选中。结合上面的#1,您只需测试nilnil;如果它不是nil,则会有一个选定的块,如果它是{{1}},则表示您没有找到(即没有)所选的块。

  6. 使用此代码后,将其转换为ARC。 (编辑/重构菜单中有一个菜单项。)然后您不必保留或释放或自动释放任何内容;大多数事情都有效。

答案 1 :(得分:0)

我想说当你从数组中删除它时,你正在释放该块,但你已经在那里放入了虚假(和不必要的)retains所以很难说出发生了什么没有看到你遗漏的代码。

通常情况下,当我从数组中移除对象并想要保持它时,我保留它。但是你总是过度保留,以至于可能不是问题,但是如果没有看到方法的其余部分,我就无法确定。

答案 2 :(得分: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行保留了一个全新的,从未使用过的Block.selectedBlock从未得到保留,当你从阵列中删除它时,它被销毁了。因此,selectedBlock指向一个旧陈旧的被破坏的内存导致崩溃。