Objective-C Blocks测试题与解析

本文通过几个具体的例子来测试Objective-C中的Blocks特性,并探讨它们在ARC(自动引用计数)和非ARC环境下的表现差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

void exampleA() {
   char a = 'A' ;
   ^{
     printf( "%c\n" , a);
   }();
}


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

    Example B

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


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

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

    Example C

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

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

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

    Example D

    typedef void (^dBlock)();
     
    dBlock exampleD_getBlock() {
       char d = 'D' ;
       return ^{
         printf( "%c\n" , d);
       };
    }
     
    void exampleD() {
       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

    typedef void (^eBlock)();
     
    eBlock exampleE_getBlock() {
       char e = 'E' ;
       void (^block)() = ^{
         printf( "%c\n" , e);
       };
       return block;
    }
     
    void exampleE() {
       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李兴乐点击打开链接

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值