美文网首页
Blcok的使用

Blcok的使用

作者: 齊同学 | 来源:发表于2019-05-16 17:00 被阅读0次

    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对象也就不会造成循环引用,从而避免内存泄漏。

    相关文章

      网友评论

          本文标题:Blcok的使用

          本文链接:https://www.haomeiwen.com/subject/feziaqtx.html