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

Jus*_*ios 0 iphone cocoa-touch objective-c

这是我的代码简化:

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
}
Run Code Online (Sandbox Code Playgroud)

我想将所选块复制到"SelectedBlock",从块中删除块,然后再使用"SelectedBlock".当我使用这段代码时,我总是得到"EXC_BAD_ACCESS.我觉得程序在我想要它之前发布了"SelectedBlock"中的数据.我做错了什么?

更新:

感谢大家的帮助.我修好了它.

Pet*_*sey 5

Block* selectedBlock = [[[Block alloc] init] retain];
Run Code Online (Sandbox Code Playgroud)

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

// Move the block to the selected block
selectedBlock = tempBlock;
Run Code Online (Sandbox Code Playgroud)

这个评论没有意义.什么都没有从一个块移动到另一个块; 您将selectedBlock变量设置为指向从数组中获取的块.后这一点上,selectedBlocktempBlock都指向相同的块,这是阵列中的块.

// Take the block out of the array
[buildBlocks removeObjectAtIndex:i];
Run Code Online (Sandbox Code Playgroud)

该阵列拥有它包含的所有块,因此当您从阵列中删除块时,阵列会释放它.如果那是该块的唯一所有权,那么该块将被解除分配.此后对它的任何使用都是无效的.

如…

if( selectedBlock.selected )  // <---- Crashes here
Run Code Online (Sandbox Code Playgroud)

selectedBlock指向您获得的块然后从阵列中删除.假设数组是拥有它的唯一东西,那么此时它就是一个死对象,所以是的,向它发送消息会导致崩溃.

您保留了初始化的对象selectedBlock,但不保留稍后替换该对象的对象.保留该初始对象不会主动保留您分配给该变量的任何未来对象; 它只保留了那个初始对象.

您需要更改几件事:

  1. 初始化selectedBlocknil,而不是指向新块的指针.

  2. 不要随意保留东西.始终保持目的.如果你不完全理解为什么保留某些东西是正确的事情("使它不崩溃"本身不是一个可接受的理由),不要只是保留它.了解内存管理规则的高级内存管理编程指南,当你需要保留你就会知道,为什么你retain[[[Block alloc] init] retain]是不必要的.

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

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

  5. 不要问所选的块是否被选中.您只需指定一个Block指针,selectedBlock如果它已被选中,那么当您使用时selectedBlock,您已经知道它已被选中.以上#1相结合,你可以简单地测试是否selectedBlocknil; 如果不是nil,则有一个选定的块,如果是nil,则表示您没有找到(即没有)所选的块.

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