zoukankan      html  css  js  c++  java
  • Objective-C—— Block

    OC Block 其实功能就类似C语言的函数指针,js中的闭包之类的。把代码块当做一个变量就行操作,有自己的变量和作用域。

    简单看一下Block的语法和可能出现的问题:

    Block语法:

    block语法相对宽松,很多部分都可以省略,常规上我们实现一个block需要有以下几个部分

    ^ 返回值类型 参数列表 表达式

    例如

        ^int (int count){return count+1;};//返回值为int 参数为int 表达式为 count+1;
        ^void (void){NSLog(@"void");};    //返回值为void 参数void 表达式为  NSLog(@"void");

    可以看到语法相对简单,而且返回值类型可以省略那么以上两个block就变

        ^(int count){return count+1;};
        ^(void){NSLog(@"void");};

    如果不适用参数,那么返回值列表也可以省略

        ^(int count){return count+1;};
        ^{NSLog(@"void");};

    Block类型变量

    Blcok类型的变量可以接受对应的Block,上例中两个Block就需要以下两种Block类型变量接收

        int (^intBlock)(int) = ^(int count){return count+1;};
        void (^voidBlock)(void) = ^{NSLog(@"void");};

    上例中,可以看到变量定义格式

    返回值类型 (^变量名称) (返回值类型)

    如果嫌这种定义方式麻烦的话,可以使用typedef来简化定义方式

        typedef int (^typedefBlock) (int);
        typedefBlock block = ^(int count){return count+1;};

    截获变量值

    Block中,可以使用调用Block之前的变量的值,例如

        int a = 5;
        int (^intBlock)(int) = ^(int count){return count+a;};
        NSLog(@"%d",intBlock(5));
        2015-08-02 17:25:53.393 Dispatch[9970:3096937] 10

    可以看到输出结果是10,说明intBlock截获了变量a的值。

    但是如果我们想要修改a的值,就会出现错误可以自己尝试一下。

    想要修改需要在变量前添加__block修饰符,说明该变量在block中是可以被修改的。

        __block int a = 5;
        int (^intBlock)(int) = ^(int count){a = 3; return count+a;};
        NSLog(@"%d",intBlock(5));
        2015-08-02 17:33:11.629 Dispatch[10118:3136172] 8

    输出结果为8,说明已经被我们修改了。

    同样的道理,对已OC对象来说也是,如果调用方法使用该变量可以,但是对变量进行赋值操作就需要加上__block修饰符。

    Block循环引用

    循环引用出现条件,该对象持有Block的成员属性,同时在Block中使用self。这样会造成Block和对象之间的相互引用,互相都无法释放,形成内存泄露。

    @interface ViewController ()
    {
        voidBlock _voidBlock;
    }
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
       // __block int a = 5;
        _voidBlock = ^{NSLog(@"%@",self);};
        _voidBlock();
    
    }
    

     这样写编译去会提示我们self的强引用在Block中使用。

    还有一种,如果我们在Block中使用了成员属性,同样会造成内存泄露。因为成员属性是self指针指向的对象,还是在Block中持有了self。

    __weak
    为了避免这样的情况发生,我们再上面的例子中稍微修改一下

    - (void)viewDidLoad {
        [super viewDidLoad];
        
       // __block int a = 5;
        __weak ViewController *temp = self;
        _voidBlock = ^{NSLog(@"%@",temp);};
        _voidBlock();
    
    }

    使用弱引用对象就能很好的避免这种情况。

    再有就是用__block也能够避免循环。

    - (void)viewDidLoad {
        [super viewDidLoad];
        
       // __block int a = 5;
        __block ViewController *temp = self;
        _voidBlock = ^{NSLog(@"%@",temp); temp = nil;};
        _voidBlock();
    
    }

    注意这样写必须调用该Block,执行Block代码才行,如果不执行还是会造成内存泄露。

  • 相关阅读:
    seata 1.3.0 seata Global lock wait timeout
    Tika解析word文件
    我的第一款微信小程序:iteye附件下载器,希望大家好好爱惜
    读书《尸检报告》 [英]卡拉·瓦伦丁 / 中信出版集团2019-08
    读书《另一种选择》 [美] 谢丽尔·桑德伯格 / 中信出版集团2017-08
    读书《不朽的失眠》 张晓风 / 四川人民出版社2018-09
    Uniapp 修改内置组件样式无效解决方法
    Android studio中.9图片的含义及制作教程
    Diff算法
    js new一个对象的过程,实现一个简单的new方法
  • 原文地址:https://www.cnblogs.com/madpanda/p/4696403.html
Copyright © 2011-2022 走看看