目录:block的本质、变量捕获、类型、copy、__block修饰符
本质
- block本质上也是一个OC对象,它内部也有个isa指针
- block是封装了函数调用(函数地址)以及函数调用环境(参数、外部局部变量等)的OC对象
- 图示:
变量捕获
-
局部变量
类型 捕获到block内部 访问问方式 auto ✅ 值传递 static ✅ 指针传递 auto int age = 10; // auto: 自动变量,离开作用域就销毁 static int height = 100; void (^block)(void) = ^{ NSLog(@"age is %d, height is %d",age ,height); // 捕获变量(capture) }; age = 20; height = 200; block(); // age is 10, height is 200
-
全局变量
类型 捕获到block内部 访问问方式 全局变量 ❌ 直接访问 -
self
self也会被捕获到block内部,注意,self实际上是局部变量!!!指针传递
oc当中,函数方法实际上有2个隐藏参数,例(MyPerson *self,SEL _cmd),其中,self是作为局部变量传递进来的
block的类型
block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型。
- NSGlobalBlock ( _NSConcreteGlobalBlock ) 没有访问auto变量的
- NSStackBlock ( _NSConcreteStackBlock ) 访问了auto变量(需在非ARC)
- NSMallocBlock ( _NSConcreteMallocBlock ) NSStackBlock 调用了copy(需在非ARC)
每一种类型的block调用copy后的结果如下:
block类型 | 副本源的配置存储域 | 复制效果 |
---|---|---|
NSGlobalBlock | 程序的数据区域 | 什么也不做 |
NSStackBlock | 栈 | 从栈复制到堆 |
NSMallocBlock | 堆 | 引用计数增加 |
block的copy
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如:
-
blcok作为函数返回值时
MJBlock block() { int age = 10; return ^{ NSLog(@"age = %d",age); }; }
-
将block赋值给 __strong 指针时
int age = 10; void (^blcok)(void) = ^{ NSLog(@"age = %d",age); }; block();
-
block作为Cocoa API中方法名含有usingBlock的方法参数时
-
block作为GCD API的方法参数时
__block修饰符
-
作用:
- __block可以用于解决block内部无法修改auto变量值的问题
- __block不能修饰全局变量、静态变量
- 编译器会将__block变量包装成一个对象
-
内存管理:
- 当block在栈上时,并不会对 __block 产生强引用
- 当block被copy到堆时,会调用block内部的copy函数,其内部会对 __block 变量形成强引用
- 当block从堆中移除时,会调用block内部的dispose函数,其内部会自动释放引用的 __block 变量(release)
阅读量
loading...