代码改变世界

Objective-C Blocks测试题与解析

2014-04-11 17:35  Lves Li  阅读(419)  评论(0编辑  收藏  举报

Objective-C Blocks 测试

你真的理解blocks在objective-c中是如何工作的了吗,做个测试检验一下吧。

所有的测试结果已被以下版本的LLVM验证:

Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix

一下问题的选项是:都能工作;只在ARC下能工作;只在非ARC下能工作;不能执行

Example A

voidexampleA() {
  chara = 'A';
  ^{
    printf("%c\n", a);
  }();
}


选择 always works.
当block结束执行后exampleA的堆也不再继续。因此block被accocated在了
堆上或者栈上,当执行时blocks才有效。

Example B

voidexampleB_addBlockToArray(NSMutableArray*array) {
  charb = 'B';
  [array addObject:^{
    printf("%c\n", b);
  }];
}
 
voidexampleB() {
  NSMutableArray*array = [NSMutableArrayarray];
  exampleB_addBlockToArray(array);
  void(^block)() = [array objectAtIndex:0];
  block();
}


选择:只在ARC下能正常工作。
不采用ARC的时候,block是一个在exampleB_addBlockToArray的栈上的NSStackBlock 。当exampleB执行的时候,block已经不存在,因为栈已经被释放。

采用ARC机制时,block被实例化到了堆上是一个NSMallocBlock,采用自动释放方法。

Example C

voidexampleC_addBlockToArray(NSMutableArray*array) {
  [array addObject:^{
    printf("C\n");
  }];
}
 
voidexampleC() {
  NSMutableArray*array = [NSMutableArrayarray];
  exampleC_addBlockToArray(array);
  void(^block)() = [array objectAtIndex:0];
  block();
}
选择always works.

因为block中没有引用任何变量,他在执行时不需要任何声明,它被编译成了一个NSGlobalBlock。它既不在堆上又不在栈上。有点像c中的函数

 在有没有ARC下都可以工作。

Example D

typedefvoid(^dBlock)();
 
dBlock exampleD_getBlock() {
  chard = 'D';
  return^{
    printf("%c\n", d);
  };
}
 
voidexampleD() {
  exampleD_getBlock()();
}


选择 only works with ARC.

它和 example B类似。不采用ARC, block 将会创建在exampleD_getBlock 的栈上当函数返回时就无效了。在这种情况下,编译器会报以下的错误 error: returning block that lives on the local stack.

采用ARC block会被编译成一个自动释放的 NSMallocBlock.

Example E

typedefvoid(^eBlock)();
 
eBlock exampleE_getBlock() {
  chare = 'E';
  void(^block)() = ^{
    printf("%c\n", e);
  };
  returnblock;
}
 
voidexampleE() {
  eBlock block = exampleE_getBlock();
  block();
}
选择 only works with ARC.

和example D类似, 这段代码会正常编译,运行时会崩溃。更糟的情况是,如果你不检查,测试时他可能运行正常,在项目中就会崩溃。

采用ARC block会被编译成一个自动释放的 NSMallocBlock.

总结

考虑一下关键点是什么?总是采用ARC嘛。采用ARC它总能运行正常. 如果你不采用ARC, 你最好这样做 block = [[block copy] autorelease] 。 这样强制编译器深拷贝成一个 NSMallocBlock。

哈哈,它当然远没有这么简单。苹果官网是这么提示的:

Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.

原文译自http://blog.parse.com/2013/02/05/objective-c-blocks-quiz/。。不对之处各位大神请指正。新浪微博@WildCat李兴乐点击打开链接