Pat*_*ini 20 recursion objective-c objective-c-blocks automatic-ref-counting
这会导致任何类型的保留周期吗?使用安全吗?
__block void (^myBlock)(int) = [^void (int i)
{
if (i == 0)
return;
NSLog(@"%d", i);
myBlock(i - 1);
} copy];
myBlock(10);
myBlock = nil;
Run Code Online (Sandbox Code Playgroud)
rob*_*off 34
您的代码确实包含保留周期,但您可以通过myBlock
在递归基本情况(i == 0
)中设置为nil来在递归结束时中断保留周期.
证明这一点的最好方法是尝试在分配工具下运行,"停止时丢弃未记录的数据"关闭,"记录参考计数"打开,"仅跟踪活动分配"关闭.
我使用OS X命令行工具模板创建了一个新的Xcode项目.这是整个计划:
#import <Foundation/Foundation.h>
void test() {
__block void (^myBlock)(int) = [^void (int i){
if (i == 0) {
// myBlock = nil;
return;
}
NSLog(@"myBlock=%p %d", myBlock, i);
myBlock(i - 1);
} copy];
myBlock(10);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
test();
}
sleep(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后我使用上面描述的设置在Allocations仪器下运行它.然后我在Instruments中将"Statistics"更改为"Console",以查看程序输出:
2012-10-26 12:04:31.391 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 10
2012-10-26 12:04:31.395 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 9
2012-10-26 12:04:31.396 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 8
2012-10-26 12:04:31.397 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 7
2012-10-26 12:04:31.397 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 6
2012-10-26 12:04:31.398 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 5
2012-10-26 12:04:31.398 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 4
2012-10-26 12:04:31.399 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 3
2012-10-26 12:04:31.400 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 2
2012-10-26 12:04:31.401 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 1
<End of Run>
Run Code Online (Sandbox Code Playgroud)
我复制了块地址(0x7ff142c24700
),将"Console"更改为"Objects List",并将地址粘贴到搜索框中.仪器向我展示了块的分配:
Live列下的点表示程序退出时仍然分配了块.它被泄露了.我点击了地址旁边的箭头,查看了该块分配的完整历史记录:
这个分配只发生过一件事:它被分配了.
接下来,我myBlock = nil
在if (i == 0)
声明中取消注释了该行.然后我再次在探查器下运行它.系统随机化内存地址以确保安全性,因此我清除了搜索栏,然后再次检查控制台以查看此运行中的块地址.就在0x7fc7a1424700
这个时候.我再次切换到"对象列表"视图并粘贴到新地址中0x7fc7a1424700
.这是我看到的:
这次Live列下没有任何点,这意味着程序退出时块已被释放.然后我点击地址旁边的箭头查看完整的历史记录:
这一次,块被分配,释放和释放.
tc.*_*tc. 14
有一个简单的解决方案可以避免周期和过早复制的潜在需求:
void (^myBlock)(id,int) = ^(id thisblock, int i) {
if (i == 0)
return;
NSLog(@"%d", i);
void(^block)(id,int) = thisblock;
block(thisblock, i - 1);
};
myBlock(myBlock, 10);
Run Code Online (Sandbox Code Playgroud)
您可以添加包装器以获取原始类型签名:
void (^myBlockWrapper)(int) = ^(int i){ return myBlock(myBlock,i); }
myBlockWrapper(10);
Run Code Online (Sandbox Code Playgroud)
如果你想扩展它以进行相互递归,这就变得乏味了,但是我不能想到一个很好的理由这样做(一个类不会更清楚吗?).
归档时间: |
|
查看次数: |
4124 次 |
最近记录: |