- NSGlobalBlock_(全局block) -> 无参,无返回值 ->全局区 ->0x1开头
- NSMallocBlock_(堆区block) -> 函数, 对象, 访问外界 -> 0x6开头
- NSStackBlock(栈区block) -> 内有局部变量, 局部变量没有拷贝前 -> 栈区 ->拷贝后 ->堆区 -> 0x7开头
总结:
block-> 全局区
block -> 访问外界变量(copy) -> 强引用 -> 堆区
-> _weak可弱引用 -> 栈区
循环引用的解决方法
- weak-strong-dance
- _block修饰对象(需要注意的是在block内部需要置空对象,而且block必须调用)
- 传递 self作为block的参数
- NSProxy
__block ViewController *vc = self; self.cjlBlock = ^(void){ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@",vc.name); vc = nil;//手动释放 }); }; self.cjlBlock();
NSProxy
- 多继承
- (void)cjl_proxyTest{ Dog *dog = [[Dog alloc] init]; Cat *cat = [[Cat alloc] init]; CJLProxy *proxy = [CJLProxy alloc]; [proxy transformObjc:cat]; [proxy performSelector:@selector(eat)]; [proxy transformObjc:dog]; [proxy performSelector:@selector(shut)]; }
- 循环引用
self.timer = [NSTimer timerWithTimeInterval:1 target:[CJLProxy proxyWithObjc:self] selector:@selector(print) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
Block底层分析
block本质 -> 对象 -> 函数(匿名函数) -> 结构体
- block为什么需要调用 ->函数声明(_main_block_func_0)
执行具体的函数实现 -> block的FuncPtr指针 -> block - block如何获取外界变量 -> 在内部会自动生成同一个属性来保存
- __block原理 -> 外界变量会生成__Block_byref_a_0结构体 -> 保存原始变量的指针和值 -> 传给block
block三次copy分析
[NSMethodSignature signatureWithObjCTypes:"v8@?0"]
block -> 结构 -> block_layout (底层结构)
byref 结构
- 第一层 -> 用过_Block_copy -> 对象自身的copy -> 从栈区拷贝至堆区
- 第二层 -> 根据不同类型进行不同操作, -> __block -> 只有__block才有这个操作 -> _Block_byref_copy -> 对象 -> Block_byref结构体类型
- 第三层 -> 对象类型(NSString)才有 -> _Block_object_assign -> 对__block修饰的当前变量拷贝
只有__block修饰的对象, block的copy才有三层.