1

在这个讨论之后,我遇到了一个错误的访问问题;

一个循环有几个步骤:a、b、c、... x、y、z:

-(void)cycle:(float)delta{
[self stepA]
[self stepB]
// etc.
[self stepZ]
}

在某些时候,步骤 x 执行以下操作:

// IRQ is an NSMutableArray
// Self is a reference to the engine running the cycles
[IRQ addObject:^{ NSLog(@"hello! %@", self); } ];

稍后,步骤 z 是处理所有“延迟”调用:

            for (int i = 0; i < [IRQ count]; i++){
                void (^delayedCall)(void) = [IRQ objectAtIndex:i];
                delayedCall();
            }

            [IRQ removeAllObjects];

结果:EXEC_BAD_ACCESS

现在,如果步骤 x 只添加一个没有对象引用的纯字符串,如下所示,步骤 Z 可以正常工作:

[IRQ addObject:^{ NSLog(@"hello!"); } ];

最后观察,如果同一个步骤既将块添加到队列中,又遍历队列以执行块,则不会出现问题。就像对对象的引用随着步骤“丢失”:方法被留下?

我在这方面不太了解,需要更多帮助!

编辑:詹姆斯,只是尝试了以下方法来避免该参考周期:

NSString *userName = @"James";
[IRQ addObject:^{ NSLog(@"hello %@", userName); } ];

它也会发生。您的解决方案将如何应用于此?

提前致谢!

4

3 回答 3

3

当您使用语法创建块时^{},它会在堆栈上创建。要将块持久化很长一段时间(超出创建它的函数的范围),您必须将块复制到堆中:

void (^ myBlock)(void) = ^ {
    // your block code is here.
};
[IRQ addObject:[[myBlock copy] autorelease]];

如果使用 ARC,请跳过该-autorelease消息。

于 2012-06-30T23:15:57.097 回答
3

问题是块对象是在堆栈上创建的。当您希望在声明它们的范围被销毁之后使用它们时,并且如果没有为您复制块,则需要将块复制到堆中。

在这里,您将一个对象“向下堆栈”传递给一个不知道块的方法。代替

[IRQ addObject:^{ NSLog(@"hello! %@", self); } ];

[IRQ addObject:[^{ NSLog(@"hello! %@", self); } copy]];

并且EXC_BAD_ACCESS此时将消失。

但在大多数情况下,您不需要复制块!几个例子:

  1. 如果你从一个方法返回一个块(“向上堆栈”),ARC 会自动复制它。
  2. 如果调用不保留块的方法,则不需要复制块,因为它保留在范围内。示例:传递给-[NSArray sortedArrayUsingComparator:].
  3. 如果您稍后调用使用该块的方法,则该方法应负责复制该块,否则每个调用者都需要复制该块。我知道的 Apple 库中的所有方法/函数都遵循该模式。示例:完成块传递给+[UIView animateWithDuration:options:animations:completion:].
于 2012-06-30T23:17:17.987 回答
0

似乎您传入的对象..在您的示例中:self并且userName被过早地释放。这不是我期望的块行为。和我之前的回答一样,我预计问题是因为保留太多!

作为测试,您可以尝试:

NSString *userName = [@"James" retain];
[IRQ addObject:^{ NSLog(@"hello %@", userName); } ];

这将是内存泄漏,但它有助于指示对象是否正在被释放。

这是由块正在保留selfself正在保留块的“保留周期”引起的。

尝试这个:

__block typeof(self) blockSafeSelfReference = self;
[IRQ addObject:^{ NSLog(@"hello! %@", blockSafeSelfReference); } ];

如果使用 ARC,请使用__unsafe_unretained而不是__block

于 2012-06-30T23:06:02.223 回答