IMG_5751.JPG

前言

1.block上层面试
2.实际业务开发 - 问题,循环引用
3.block底层分析-结构体,block_invoke就是回调,可进行hook

种类

  1. 全局BLock,NSGlobalBlock,位于全局区,在Block内部不使用外部变量,或者只使用静态变量和全局变量。
  2. 堆Block,NSMallocBlock,位于堆区,在Block内使用变量或者OC属性,并赋值给强引用或者Copy修饰的变量。
  3. 栈Block,NSStackBlock,位于栈区,与堆Block一样,在Block内使用变量或者OC属性,但不能赋值给强引用或者Copy修饰的变量。

    举例

    demo1

  • 等号前的block相当于指向了等号后的block的内存空间
  • 类似 NSObject *obj = [NSObject alloc] 中的obj指向了=后的内存空间

image.png

demo2

  • 以下打印结果为1 —> 3 —> 4 —> 5
  • block捕获对象时,引用计数+1;从栈区block拷贝到堆区时,block会再次+1
  • 首先栈内生成一个变量,对捕获而来的对象存储,然后block_ref从栈区拷贝到堆区,相当于又复制了一份
  • 第二步骤 = 第三步骤 + 第四步骤

image.png

demo3

  • 内存拷贝的理解
    • 建立一个栈区block,同时自定义个block(结构体),此时两个block指向同一内存空间,再将block的invoke置为nil,执行strongBlock1()则发生崩溃
    • 将赋值改为copy则可以避免崩溃id__strong strongBlock = [weakBlock copy],此时栈block已经被拷贝到堆区,再赋值给_LGBlock,执行invoke = nil,不影响拷贝后的strongBlock1()

image.png

demo4

  • 此处代码执行会崩溃,原因是堆block超出作用域被释放了
  • strongBlock 加__weak 时,为栈block,压栈进栈帧,作用域为整个函数,所以不会崩溃

image.png
未命名文件 (35).jpg

循环引用

  • 相互持有导致retainCount无法减少,无法释放

image.png
image.png

  • 一般我们通过weakSelf,strongSelf来解决循环引用,但也有其它方式,如下例
  • 强弱共舞
  • __block ViewController *vc = self
    • vc持有了self ,作用域在^{}中,使用完要置为nil,否则会出现self -> block -> vc -> self,循环引用
    • vc作用域初始在栈帧中,作用域是外部{},后被block持有了,引用计数又增加了1

image.png

  • 或者将self当做参数传递,都可以解决循环引用问题

image.png

demo5

  • staticSelf全局静态变量,将weakSelf赋值给staticSelf,是否会引起循环引用?
  • weakSelf和self是映射关系,指向同一片内存空间
  • 将weakSelf赋值给全局静态变量,相当于staticSelf对self进行了持有,导致了循环引用 ```objectivec
  • (void)blockWeakstatic { // 是同一片内存空间 __weak typeof(self) weakSelf = self; staticSelf = weakSelf; // staticSelf_ -> weakSelf -> self } ```

  • weakSelf.doStudent又对strongSelf进行了持有,引用计数进行了+1,导致循环引用 ```objectivec

  • (void)block_weak_strong { __weak typeof(self) weakSelf = self; self.doWork = ^{
    1. __strong typeof(self) strongSelf = weakSelf;
    2. weakSelf.doStudent = ^{
    3. NSLog(@"%@", strongSelf);
    4. };
    5. weakSelf.doStudent();
    }; self.doWork(); } ```