Bre*_*ent 6 objective-c objective-c-blocks
在Objective-C中通过块捕获变量的语义是什么?
#import <Foundation/Foundation.h>
#include <stdio.h>
int main()
{
NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; ++i) {
int j = i;
[arr addObject:^(void) {printf("%d %d\n", i, j); }];
}
for (void (^blk)(void) in arr) {
blk();
}
}
Run Code Online (Sandbox Code Playgroud)
我正在考虑打印这样的东西:
100 0
100 1
...
100 99
Run Code Online (Sandbox Code Playgroud)
相反,它打印:
99 99
99 99
...
99 99
Run Code Online (Sandbox Code Playgroud)
怎么可能它的解释j是平等的99?j在for循环之外甚至没有活着.
您99 99多次看到的原因仅仅是由于未定义的行为。
让我们以第一个 for 循环为例:
for (int i = 0; i < 100; ++i) {
int j = i;
dispatch_block_t block = ^(void) {printf("%d %d\n", i, j); };
[arr addObject:block];
}
Run Code Online (Sandbox Code Playgroud)
[为了清楚起见,我已经拉出了块。]
在这个 for 循环中,块被创建。它是在堆栈上创建的,并且永远不会移动到堆中,因为没有块的副本可以这样做。
每次在 for 循环中,很可能(好吧,确实如此)相同的堆栈空间用于该块。然后将块的地址(在堆栈上)添加到arr. 每次都是同一个地址。但每次都是块的新实现。
一旦退出第一个 for 循环,arr包含相同的值 100 次。该值指向最后创建的块,该块仍在堆栈中。但它指向堆栈上的一个块,该块不再安全访问,因为它超出了范围。
然而,在这个例子中,完全靠运气(好吧,简单的代码)被块占用的堆栈空间没有被重用。所以当你去使用这个块时,它“有效”。
正确的解决方案是在将块添加到数组时进行复制。通过致电copy或让 ARC 为您执行此操作。这样,块被复制到堆中,并且您有一个引用计数块,该块将根据数组和创建它的范围的需要而存在。
如果你想更多地了解块的工作原理并更深入地理解这个答案,那么我建议我的解释在这里:
http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/ http://www.galloway.me.uk/2012/10/a-look-inside- blocks-episode-2/ http://www.galloway.me.uk/2013/05/a-look-inside-blocks-episode-3-block-copy/
| 归档时间: |
|
| 查看次数: |
508 次 |
| 最近记录: |