zoukankan      html  css  js  c++  java
  • [译] Block 小测验

    本文来源于 ParseBlog 的其中一篇博文 《Objective-C Blocks Quiz》

    如果您觉得我的博客对您有帮助,请通过关注我的新浪微博  MicroCai 支持我,谢谢!


    你想知道Objective-C中blocks是怎么工作的吗?那么让我们通过几个测试题来了解下吧。 
    本文所有的例子都经过以下版本的LLVM检验过:

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

    Example A

     
    1. void exampleA() {
    2. char a = 'A';
    3. ^{
    4. printf("%c ", a);
    5. }();
    6. }
    1. always works ?
    2. only works with ARC ?
    3. only works without ARC ?
    4. never works ?
     

    Example B

     
    1. void exampleB_addBlockToArray(NSMutableArray *array) {
    2. char b = 'B';
    3. [array addObject:^{
    4. printf("%c ", b);
    5. }];
    6. }
    7. void exampleB() {
    8. NSMutableArray *array = [NSMutableArray array];
    9. exampleB_addBlockToArray(array);
    10. void (^block)() = [array objectAtIndex:0];
    11. block();
    12. }
    1. always works ?
    2. only works with ARC ?
    3. only works without ARC ?
    4. never works ?
     

    Example C

     
    1. void exampleC_addBlockToArray(NSMutableArray *array) {
    2. [array addObject:^{
    3. printf("C ");
    4. }];
    5. }
    6. void exampleC() {
    7. NSMutableArray *array = [NSMutableArray array];
    8. exampleC_addBlockToArray(array);
    9. void (^block)() = [array objectAtIndex:0];
    10. block();
    11. }
    1. always works ?
    2. only works with ARC ?
    3. only works without ARC ?
    4. never works ?
     

    Example D

     
    1. typedef void (^dBlock)();
    2. dBlock exampleD_getBlock() {
    3. char d = 'D';
    4. return ^{
    5. printf("%c ", d);
    6. };
    7. }
    8. void exampleD() {
    9. exampleD_getBlock()();
    10. }
    1. always works ?
    2. only works with ARC ?
    3. only works without ARC ?
    4. never works ?
     

    Example E

     
    1. typedef void (^eBlock)();
    2. eBlock exampleE_getBlock() {
    3. char e = 'E';
    4. void (^block)() = ^{
    5. printf("%c ", e);
    6. };
    7. return block;
    8. }
    9. void exampleE() {
    10. eBlock block = exampleE_getBlock();
    11. block();
    12. }
    1. always works ?
    2. only works with ARC ?
    3. only works without ARC ?
    4. never works ?

     

    解析

    Example A: always works

    不管在 ARC 还是 MRC 下,不论 block 存放在 stack 还是 heap 内存中,当example A 被调用时,block 仍然有效,都能正常执行.

    Example B: only works with ARC

    在 MRC 下,exampleB_addBlockToArray 中的 block 是 NSStackBlock 类型,存放在stack内存中。当执行 exampleB 时,stack 内存被释放,block 失效.

    在 ARC 下,block 是 autoreleased NSMallocBlock 类型,存放在 heap 内存中,所以 Exmaple B only works with ARC.

    Example C: always works

    当 block 不需要从外部获取变量时,它不需要在 runtime 设置任何状态。此时,block 被编译成 NSGlobalBlock 类型,放在内存 data 段,就像 C 函数一样,属于代码的一部分,所以 always works.

    Example D: only works with ARC

    这题有点类似于 Example B. 在 MRC 下,exampleD_getBlock 中的block 会被创建在 stack 内存中,当函数返回时,block马上失效。鉴于本题的错误实在太明显,编译器在编译时,就会抛出错误 error: returning block that lives on the local stack.

    而在 ARC 下,block 会被编译成 autoreleased NSMallocBlock 类型,存放于 heap 内存中。

    所以 only works with ARC.

    Example E: only works with ARC

    本题类似于 Example D,区别在于本题代码不会出现编译错误,而是在运行时才会崩溃。更槽糕的是,如果你关闭了编译器优化选项,代码运行正常,而无法发现这个隐藏的bug。

    而在 ARC 下,block 会被编译成 autoreleased NSMallocBlock 类型,存放于 heap 内存中。

    所以 only works with ARC.


     

    总结

    以上这么多例子告诉我们什么?告诉我们要使用ARC!在ARC下,block总能正确运行。如果你不用ARC,最好能保证在 stack 内存中声明定义的block,能够拷贝到heap内存,保证block的正常运行。

    当然,事情并不是这么简单,看苹果官方文档

    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.

  • 相关阅读:
    Django模型层进阶
    Django模型层相关
    BOM与DOM
    JavaScript入门
    HTML基础
    子查询/联合分组/all与any/视图/事务
    表的查询
    mysql的多表关系
    Mysql基本操作
    Spider_基础总结2_Requests异常
  • 原文地址:https://www.cnblogs.com/H7N9/p/4943757.html
Copyright © 2011-2022 走看看