iOS底层原理笔记 - block的类型

109 阅读2分钟

Block的类型

一、block的三种类型

  • NSGlobalBlock

  • NSStackBlock

  • NSMallocBlock

Untitled.png


int age_;

int height_;


void test1() {

    int age1 = 10;

    void (^block1)(void) = ^{

        NSLog(@"%d", age1);

    };

    age1 = 20;

    block1();

    

    NSLog(@"%@",[block1 class]);

 }


void test2() {

    static int age2 = 10;

    void (^block2)(void) = ^{

        NSLog(@"%d", age2);

    };

    age2 = 20;

    block2();

    

    NSLog(@"%@",[block2 class]);

 }



void test() {

    age_ = 10;
    height_ = 10;

    void (^block)(void) = ^{
        NSLog(@"age = %d; height = %d", age_, height_);
    };

    age_ = 20;
    height_ = 20;
    block();
    NSLog(@"%@", [block class]);

}



int main(int argc, const char * argv[]) {

    @autoreleasepool {

        test1();  //__NSMallocBlock__
        test2();  //__NSGlobalBlock__
        test();   //__NSGlobalBlock__

    }

    return 0;

}

Untitled 1.png

每种类型的block调用结果如下:

Untitled 2.png

二、block的copy

在arc环境下,编译器会根据情况自动将栈上的block复制到堆上,如以下情况:

  1. block作为函数返回值的时候

  2. 将block赋值给__strong指针的时候

3. block作为CocoaAPI中方法名含有usingblock的方法参数时

4. block作为GCD API的方法参数时

MRC下的block属性的建议写法:


**@property** (**copy**, **nonatomic**) **void** (^blcok)(**void**);

ARC下的block属性的建议写法:


@property (copy, nonatomic) void (^blcok)(void);
@property (strong, nonatomic) void (^blcok)(void);

三、对象类型的auto变量

当block内部访问了对象的auto变量时:

  • 如果是在栈上,将不会对auto变量产生强引用

  • 如果block被拷贝到堆上

    - 会调用block内部的copy函数

    - copy函数内部会调用_Block_object_assign函数

- _Block_object_assign函数会根据auto变量的修饰符( __strong、 __weak、 __unsafe_unretained)做出相应操作,形成强引用(retain)或弱引用**

  • 如果block从堆上移除

    - 会调用block内部的dispose函数

    - dispose函数内部会调用_Block_object_dispose函数

**- _Block_object_dispose函数会自动释放auto变量(release)

    

    | 函数 | 调用时机 |

    | --- | --- |

    | copy | 栈上的block复制到堆时 |

    | dispose | 堆上的block被废弃时 |

    在使用clang转换OC为C++代码时,可能会遇到以下问题:

    cannot create __weak reference in file using manual reference

    解决方案:支持ARC、指定运行时系统版本,比如

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m