Block 定义
block 的循环引用问题
warning 如果block (block只要是copy的就会在堆中) 在堆中, block引用外界的对象, 会导致循环引用
typeof可以获取括号中传递的值的真实类型
typeof(10) a = 10; == int a = 10;
如果是用__weak修饰, 当对象销毁之后会自动将变量的值设置为nil
- 如何在开发中,避免block出现循环引用呢
- 1>每次碰到self的时候,要小心,需要思考一下
- 2>充分利用dealloc方法
- 解决方法:
__weak typeof(self) weakSelf = self;
为了保证代码的安全性,苹果在设计block的时候
- block引用外部变量时,默认会做copy操作,copy本身也会做一次强引用
- 在现在的代码中,如果block中有对self的强引用,出现循环引用的情况
- 解决方法,在oc中,对象默认都是强引用,__weak可以变成弱引用
block 的定义
/*定义属性,block属性可以用strong修饰,也可以用copy修饰 */
@property (nonatomic, strong) void(^onBtnClick)(void); //无参无返回值
@property (nonatomic, strong) void(^myBlock1)(NSString *); //带参数无返回值
@property (nonatomic, strong) NSString *(^myBlock2)(NSString *); //带参数与返回值
// block被当做方法的参数:
格式:(block类型)参数名称
- (void)test:(void(^)())testBlock //无参无返回值
- (void)test1:(void(^)(NSString *))testBlock //带参数无返回值
- (void)test2:(NSString *(^)(NSString *))testBlock //带参数与返回值
// 使用typedef定义block :
typedef void(^myBlock)(); //以后就可以使用myBlock定义无参无返回值block
typedef void(^myBlock1)(NSString *); //使用myBlock1定义参数类型为NSString的block
typedef NSString *(^myBlock2)(NSString *); //使用myBlock2定义参数类型为NSString,返回值
// 也为NSString的block
// 定义属性
@property (nonatomic, strong) myBlock testBlock;
// 定义变量
myBlock testBlock = nil;
// 当做参数
- (void)test:(myBlock)testBlock;
3、block访问和修改变量时的变化
- block里面可以访问全局变量
- block访问全局变量,不会修改全局变量的地址
block里可以访问外部局部变量
block访问外部局部变量,会修改外部局部变量的地址
block访问外部局部变量时,会将该局部变量复制一份到自己的内部(堆区),自己用的时候用自己内部的,外部如果使用,用栈区的
- block里可以修改全局变量
- block里不可以修改外部局部变量(是以const的形式复制过来的)
- 如果我硬是要修改外部局部变量,那么就在外部局部变量前面加一个__block
- 被__block修饰的外部局部变量,会复制一份到block内部,然后如以后用该变量,用的都是block内部的
4、前提是ARC : Block访问外部的变量
- ARC环境下,单纯的定义一个block存储在全局区 <NSGlobalBlock: 0x1045c60b0>
- ARC环境下,block访问外部的变量时block存储在堆区 <NSMallocBlock: 0x7fa8fd00c1b0>
- 在block访问这个变量之前,变量在栈区
== 0x7fff53c73bfc - 在block内部访问这个变量时,变量会被block拷贝到堆区
0x7fe851517880
5、前提是ARC : Block修改外部的变量
- ARC环境下,当block修改外部变量的时候,会在堆区
<NSMallocBlock: 0x7f82ac8a6130> - 在block的外面,即使你使用__block修饰了,那么他的地址依然不变,在栈区
0x7fff5e101bf8 - 在block内部修改外部的变量时,使用__block修饰了外部的变量之后,外部的变量会在堆区 0x7f9d10e0bcc8
6、在MRC模式下:
- block 变量本身在常量/全局区
- 在block中访问局部变量,变量的地址发生了变化但存储空间没有发生变化还是在栈区 ,block本身的地址也变化到栈区
- block在修改局部变量,变量的地址不变化,block本身的地址变化到栈区
- *
block的循环引用问题
- MRC 使用 __block 修饰
- ARC下 使用 __weak修饰
- 在block中使用self时 要把self 搞成弱引用
把self搞成弱引用的__weak ViewController *weakSelf = self;
2.把__weak是把指针搞成弱指针(引用计数不加1) : 就是告诉Block,你在引用(Copy)我的时候,别想给我的引用计数加1
__weak.ViewController *weakSelf = self;
1.在使用Block的时候,Block在访问外部的对象时,会把对象进行一次Cpoy操作;但是,Block的Copy操作会把引用计数加1.那么此时Block就会对外部的对象有强引用;如果这个外部的对象正好是self,那么Block就会对self有强引用.此时,”很容易造成”Block的循环引用
2.__weak是把指针搞成弱指针(引用计数不加1) :
就是告诉Block,你在引用(Copy)我的时候,别想给我的引用计数加
1
3.分析 : 不用__weak造成循环引用的情况
已知 : Block(op) 对 self 有强引用
求 : 满足循环引用的条件?
答: self -> queue/OPCache -> op -> self
4.队列里面的操作执行完了以后,就会把操作从队列移除,此时,这个循环引用就解除了
5.图片下载完成之后,我们手动的把下载操作从操作缓存池移除,此时,这个循环引用也就解除了