Blcok的使用

Block介绍

  • 对象与对象之间的通信方式

  • 代理-协议,通知,Block。

  • 三种通信方式都实现了对象之间的解耦合。

  • 通知的通信方式是1对多。

  • 代理、Block是1对1

  • Block介绍

  • Block是iOS4.0之后新增的一种语法结构,也称为“闭包”。

  • Block是一个匿名的函数代码块,此代码块可以作为参数传递给其他对象。

  • 可以把block当做Objective-C的匿名函数,block是OC中的一种数据类型,^是block的特有标记

  • Block格式说明

  • (返回类型)(^block名称)(参数类型)=^(参数列表){代码实现};

  • 如果没有参数,等号后面参数列表的()可以省略。

  • Block的3种类型

  • 不管在ARC还是MRC环境下,block内部如果没有访问外部变量,这个block是全局block__NSGlobalBlock__,形式类似函数,存储在内存中的代码区。

  • MRC下,block内部如果访问外部变量,这个block是栈block__NSStackBlock__,存储在内存中的栈上。

  • MRC下,block内部访问外部变量,同时对该block做一次copy操作,这个block是堆block__NSMallocBlock__,存储在内存中的堆上。

  • ARC下,block内部如果访问外部变量,这个block是堆block__NSMallocBlock__,存储在内存中的堆上,因为在ARC下,默认对block做了一次copy操作。

局部变量

局部自动变量,在Block中可被读取。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值,Block此时对局部变量只是做了值传递的操作。

static 修饰的全局变量

因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存地址读出,获取到的是最新值,而不是在定义时copy的常量

__block __weak __strong 这都是做什么的

__block 修饰的变量

某些场景下,我们需要在Block内部对外部变量进行修改。这时需要使用__block来修饰该变量实现在Block内部的修改,此时Block是复制其引用地址来实现访问的。

比较__weak 和 __strong

这边用AFN中的一段代码

__weak __typeof(self)weakSelf = self;

AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    __strong __typeof(weakSelf)strongSelf = weakSelf;
    strongSelf.networkReachabilityStatus = status;
    if (strongSelf.networkReachabilityStatusBlock) {
        strongSelf.networkReachabilityStatusBlock(status);
    }
};

__weak

  • 我们在使用Block时,有时候会用到self,而Block内部对self默认都是强引用。在ARC下,编译器将Block从栈区拷贝到堆区,Block会强引用和持有self,而self 也会强引用和持有Block,于是就造成了循环引用。
  • 此时就需要使用__weak,在修饰变量时,修饰符修饰变量self,让 block 不强引用self,从而破除循环。
__weak typeof(self) weakSelf = self;

self.passValueBlock = ^(NSString *string){
    dispatch_async(dispatch_get_main_queue(), ^{
       weakSelf.pointView.startLabel.text = string;
   });
}

弱引用不会影响对象释放,当一个对象被释放是,所有指向它的弱引用会被置空,也避免出现野指针。

__strong

  • 上面提到,__weak很好的解决retain Cycle,但还是会存在一些隐患。不知道self什么时候被释放,为了保证在Block内部不会被释放,所以使用__strong修饰。
  • Block内部对对象采用strong修饰后,既使原持有对象在block外部已经被释放,但Block内部扔能持有,于是执行完Block后,该对象才被dealloc。
总结:weakSelf是为了Block不持有self,避免循环引用,而再声明一个strongSelf是因为一旦进入Block执行,就不允许self在这个执行过程中释放。Block执行完后这个strongSelf会自动释放,没有循环引用问题。

最后,使用Block时的注意事项

  • Block内部不能直接修改局部变量

  • Block内部可以访问外部的变量, 默认是将其拷贝到其数据结构中来实现访问的, 属性是只读的. Block内部不能修改外面的局部变量.

  • 如果要修改需要对要修改的局部变量用__block修饰, 这样局部变量就可以在Block内部修改了,Block是复制其引用地址来实现访问的

  • 当Block里面的出现self,造成的循环引用

  • 循环引用就是当self 拥有一个Block的时候,在Block中又调用self的方法。形成了你中有我,我中有你,造成谁都无法将谁释放。从而发生内存泄漏。

解决方法:
__weak typeof (self) weakSelf = self;
  • 定义一个weakSelf变量并加上__weak修饰符,在Block代码块中,所有需要self的地方都用weakSelf来替代。这样就不会增加引用计数,所以Block持有self对象也就不会造成循环引用,从而避免内存泄漏。

推荐阅读更多精彩内容