0

我有一个需要一个块的方法:

- (void)methodWithBlock:(blockType)block

该方法从复制开始block,因为它在使用它之前会执行异步操作,否则它将被丢弃。然后它在另一个块中调用该方法,然后在该块中释放它。总结:

- (void)methodWithBlock:(blockType)block
{
    block = [block copy];
    [something asyncStuffWithFinishedBlock:^{
        // ..
        block();
        [block release];
    }];
}

CLANG 抱怨“块”的内存泄漏。如果我删除了复制和释放语句,该块将在它被调用时消失——至少早期的崩溃表明情况就是这样。

这是错误的做事方式吗?如果是这样,我应该如何执行上述操作 - 即方法中的块语句中的块回调?我不能将块存储为实例变量,因为在异步部分发生时,可以使用不同的参数重复调用该方法。

4

2 回答 2

3

首先,-copyand-release应该是不必要的。该-asyncStuffWithFinishedBlock:方法必须复制传递给它的块。当一个块被复制并引用其他块对象时,它也会复制这些块对象。您需要弄清楚您所看到的崩溃的真实性质。

其次,你释放了错误的东西。 [block copy]不会修改block-copy消息的接收者)以某种方式将其变成副本。它返回该块的副本。您希望在调用语句 ( block();) 和释放时都引用这个返回的副本。

所以,你可以这样做:

block = [block copy];
[something asyncStuffWithFinishedBlock:^{
    // ..
    block();
    [block release];
}];

请注意重新分配局部block变量以指向副本。

可以这样想:您是否会以尝试复制该块的方式复制字符串?你会怎么做:

[someString copy];
// ... use someString ...
[someString release];
于 2012-06-05T09:25:00.730 回答
1

我认为你不应该那样做release内部的块。您假设该块仅被调用一次。但仅从代码中,我们不知道。可能是该方法根本不执行该块,在这种情况下您将不会释放,因此会泄漏。也可能是该方法多次执行该块,在这种情况下您将过度释放。

如果你真的想复制它,你需要像这样在块外释放它(保留一些东西的范围应该负责释放它):

- (void)methodWithBlock:(blockType)block
{
    block = [block copy];
    [something asyncStuffWithFinishedBlock:^{
        // ..
        block();
    }];
    [block release];
}

(这与它的论点无关asyncStuffWithFinishedBlock;根据内存管理规则,如果它需要保留它更长的时间,它需要保留或复制它(对于它需要复制它的块)。)

但是,正如 Ken Thomas 指出的那样,您不必在此方法中复制它,因为您没有将块存储在任何地方。asyncStuffWithFinishedBlock如果需要异步运行,则应复制其参数块;并且该块捕获的任何块都应在复制时被复制。

于 2012-06-05T18:59:17.703 回答