首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >块文字是否应保留引用的堆分配的块

块文字是否应保留引用的堆分配的块
EN

Stack Overflow用户
提问于 2011-03-27 07:43:15
回答 2查看 1.8K关注 0票数 16

考虑以下代码:

代码语言:javascript
复制
// 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由以下各项定义:

代码语言:javascript
复制
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)如果这是预期的行为,那么解释它的文档在哪里?

1

2

3

脚注:在我的测试中,运行此代码的结果是对block2_copied()的无限递归调用,因为block1_copied()与block2_copied具有相同的内存地址。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-03-27 13:09:28

This is the specification。它现在有点过时,没有正常规范的形式主义。然而,在C工作组中已经提出了块,并且已经在该上下文中讨论了更正式的规范。

具体地说,该规范说:

Block_copy操作符保留块表达式中引用的自动存储变量中保存的所有对象(如果在垃圾收集下运行,则形成强引用)。假定__block存储类型的对象变量保存普通指针,而不提供保留和释放消息。

因此,您看到的行为是正确的,尽管这绝对是一个陷阱!

在复制数据块之前,数据块不会保留任何内容。就像在堆栈上开始的块一样,这在很大程度上是基于性能的决策。

如果您要将代码更改为:

代码语言:javascript
复制
SimpleBlock block2_copied = [block2 copy];
[block1_copied release];

它的行为符合预期。

静态分析器应该捕捉到这一点,但没有(请使用file a bug)。

票数 5
EN

Stack Overflow用户

发布于 2011-03-27 09:09:20

我注意到,普通物体似乎也会发生同样的情况。这段代码:

代码语言:javascript
复制
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还没有被复制。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5446187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档