iOS block探究(一)

921 阅读2分钟

block分类

  1. NSGlobalBlock(全局block)
  • 全局区
  • 在block内部不实用外部变量,或者只使用静态变量和全局变量 代码:
static int a = 0;
void (^block)(void) = ^{
 NSLog(@" %d",a);
};
  1. NSMallocBlock(堆区block)
  • 堆区
  • 在block内部使用变量或者OC属性,并且赋值给强引用或者Copy修身的变量 代码:
int a = 0;
void (^block)(void) = ^{
 NSLog(@" %d",a);
};
  1. NSStackBlock(栈区block)
  • 栈区
  • 在block内部使用变量或者OC属性,但是不能赋值给强引用或者Copy修身的变量,也就是弱引用修饰。 代码:
int a = 10;
void ( __weak ^block)(void) = ^{
NSLog(@" %d",a);
};

block循环引用

  • 为什么会产生循环引用?

A和B正常释放:

截屏2021-08-21 下午3.02.57.png A强持有B,B强持有A,无法释放

截屏2021-08-21 下午3.04.06.png

  • block循环引用案例

截屏2021-08-21 下午3.11.00.png 当我们采用上面的代码时候,就会出现循环引用。编译器也会提示 那么如何解决呢?

  • 使用弱引用__weak

截屏2021-08-21 下午3.16.21.png 但是还有一个问题,当我们block是一个耗时操作,这个时候我们又退出页面,就会发现name为空。因为这个时候controller已经释放,那么如何解决这个问题

  • 使用弱引用__weak + __strong

截屏2021-08-21 下午3.19.30.png 这个时候,有这样的应用关系self->block->weaSelf->strongSelf->Self.因为strongself是一个临时变量,需要block执行完成后会销毁。这样既能打破循环,又能避免提前释放。

  • 手动释放

截屏2021-08-21 下午3.26.38.png self -> block -> vc -> self,我们可以通过一个中间变量手动释放,当block执行完成后,把vc=nil,这样就可以打破循环

  • block传参

截屏2021-08-21 下午3.30.15.png 我们知道OC的方法都默认有一个self参数,同样block我们也可以通过传入参数这种方式,避免出现循环引用。

block案例分析

案例一

static ViewController *staticSelf_;
- (void)blockWeak_static {
// 是同一片内存空间
__weak typeof(self) weakSelf = **self**;
staticSelf_ = weakSelf;
// staticSelf_ -> weakSelf -> self
}

上面的代码是否会产生循环应用?答案是会产生。 首先我们分析staticSelf_ -> weakSelf -> selfstaticSelf_是一个全局静态变量,退出界面后不会释放。所以导致self不会释放。所以__weak不一定不会导致内存泄漏。

案例二:

截屏2021-08-21 下午3.52.44.png 上面的代码也会产生内存泄漏,strongSelf被dostudent持有,导致strongSelf无法释放。self->weakSelf->strongSelft->doStudent->WeakSelf.