void (^block) (); int a; if (1 == a) { block = ^{ NSLog(@"1"); }; } else { block = ^{ NSLog(@"others"); }; } block();
定义在if及else语句中的2个block都会被分配到栈内存中。编译器会给每个block分配好栈内存,然而等离开相应的作用域后,编译器有可能会把分配给block的栈内存覆写掉。因此,上面的block只能保证其在if及else语句作用域内有效,出了作用域有crash的可能。
解决办法:给块对象发送copy消息,如此就把块从栈拷贝到堆上了。拷贝后,块可以在定义的作用域外使用。一旦拷贝到堆上后,块就变成了带引用计数的对象了。后续的copy的操作都不会真的执行copy,只会增加块对象的引用计数。当块的对象的引用计数为0时,分配在块上的对象会像其他对象一样被系统回收。然而分配在栈内存的块,栈内存会被系统自动回收。所以以上代码是不安全的。使用copy之后,就不会出现crash问题了。
void (^testBlock) (); int b; if (1 == b) { testBlock = [^{ NSLog(@"1"); } copy]; } else { testBlock = [^{ NSLog(@"others"); } copy]; }
块可以分配在栈或堆上,也可以是全局的。分配在栈上的块可以拷贝到堆里,这样子,就可以和标准的OC对象一样,具有引用计数了!
查阅资料:Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法