考虑以下代码:
// t included so block1 is a stack block. See [1] below
int t = 1;
SimpleBlock block1 = ^{ NSLog(@"block1, %d", t); };
// copy block1 to the heap
SimpleBlock block1_copied = [block1 copy];
// block2 is allocated on the stack, and refers to
// block1 on the stack and block1_copied on the heap
SimpleBlock block2 = ^{
NSLog(@"block2");
block1_copied();
block1();
};
[block1_copied release];
// When the next line of code is executed, block2_copied is
// allocated at the same memory address on on the heap as
// block1_copied, indicating that block1_copied has been
// deallocated. Why didn't block2 retain block1_copied?
SimpleBlock block2_copied = [block2 copy];
block2_copied();
[block2_copied release];
其中,出于完整性考虑,SimpleBlock由以下各项定义:
typedef void (^SimpleBlock)(void);
正如代码中的注释所指出的,我的测试(使用GCC 4.2和LLVM2.0)显示,在调用block2 copy时,block1_copied被释放,但是根据我已经阅读的文档1,3,块是objective-c对象,并且块保留它们引用2的objective-c对象。
此外,请注意,当复制block2时,其对block1的引用也会更改为对block1的新副本(与block1_copied不同)的引用,因为块会复制它们引用的任何块2。
那么,这是怎么回事?
A)如果块保留它们引用的objective-c对象,并且块是objective-c对象,为什么在block2超出作用域之前释放block1_copied?
B)如果块复制它们引用的块,并且如果向堆分配的块发送-(Id)副本实际上只是增加其保留计数,为什么在block2超出作用域之前释放block1_copied?
C)如果这是预期的行为,那么解释它的文档在哪里?
脚注:在我的测试中,运行此代码的结果是对block2_copied()的无限递归调用,因为block1_copied()与block2_copied具有相同的内存地址。
发布于 2011-03-27 13:09:28
This is the specification。它现在有点过时,没有正常规范的形式主义。然而,在C工作组中已经提出了块,并且已经在该上下文中讨论了更正式的规范。
具体地说,该规范说:
Block_copy操作符保留块表达式中引用的自动存储变量中保存的所有对象(如果在垃圾收集下运行,则形成强引用)。假定__block存储类型的对象变量保存普通指针,而不提供保留和释放消息。
因此,您看到的行为是正确的,尽管这绝对是一个陷阱!
在复制数据块之前,数据块不会保留任何内容。就像在堆栈上开始的块一样,这在很大程度上是基于性能的决策。
如果您要将代码更改为:
SimpleBlock block2_copied = [block2 copy];
[block1_copied release];
它的行为符合预期。
静态分析器应该捕捉到这一点,但没有(请使用file a bug)。
发布于 2011-03-27 09:09:20
我注意到,普通物体似乎也会发生同样的情况。这段代码:
NSNumber *foo = [[NSNumber alloc] initWithInt:42];
void(^block)(void) = ^{ NSLog(@"foo = %@", foo); };
[foo release];
NSNumber *foo2 = [[NSNumber alloc] initWithInt:43];
void(^block_copy)(void) = [block copy];
block_copy();
打印"foo = 43“
这可能是预期的行为。引用苹果的文档:
复制块时,如有必要,将复制该块中对其他块的任何引用
在block1_copy
发布的时候,block2
还没有被复制。
https://stackoverflow.com/questions/5446187
复制相似问题