Block的底层原理

  • NSGlobalBlock_(全局block) -> 无参,无返回值 ->全局区 ->0x1开头
  • NSMallocBlock_(堆区block) -> 函数, 对象, 访问外界 -> 0x6开头
  • NSStackBlock(栈区block) -> 内有局部变量, 局部变量没有拷贝前 -> 栈区 ->拷贝后 ->堆区 -> 0x7开头

总结:
block-> 全局区
block -> 访问外界变量(copy) -> 强引用 -> 堆区
-> _weak可弱引用 -> 栈区

循环引用的解决方法

  1. weak-strong-dance
  2. _block修饰对象(需要注意的是在block内部需要置空对象,而且block必须调用)
  3. 传递 self作为block的参数
  4. 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

  1. 多继承
- (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)];
}
  1. 循环引用
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本质 -> 对象 -> 函数(匿名函数) -> 结构体

  1. block为什么需要调用 ->函数声明(_main_block_func_0)
    执行具体的函数实现 -> block的FuncPtr指针 -> block
  2. block如何获取外界变量 -> 在内部会自动生成同一个属性来保存
  3. __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才有三层.

你可能感兴趣的:(Block的底层原理)