• iOS中Blocks的介绍


    1. 什么是Blocks

          Blocks是C语言的扩充功能。如果用一句话来概括就是:带有自动变量的匿名函数。

          第一次看见Blocks的时候,感觉很类似C语言的函数指针,尤其是Block类型变量,更是有极强的相似度。但Blocks不是一个指针,而是一个不带名字的函数,它允许开发者在两个对象之间将任意的语句当作数据进行传递,同时它又能获得上下文的信息(闭包Closure),所以在一些场合使用Blocks很方便简洁。


    2. Block语法

          我们先来看一个例子吧。

          ^int(int count){return count++;}

          这个Block非常简单,就是把计数器加一,但麻雀虽小,五脏俱全,语法上一个元素都没漏掉。首先是^符号(插入符号caret),然后依次是是返回值类型,参数列表,表达式。

          ^            int                  (int count)              {return count++;}

        caret    返回参数          参数列表               表达式

          齐全的Block就是这些内容了,不同的Block的表达式的复杂程度各异,但元素就是这么多了。

          不过很多时候我们会遇到没有返回参数,或者没有传入参数,甚至既没有传入参数也没有返回参数的情况。这个时候Block可以省略相关的内容,就是说相对应的那一块不用写了。比如:

          没有返回参数,可能就会写成:^(int count){printf("count=%d", count);}

          没有参数列表,可能会写成:^int{return 1;}

          既没有返回参数也没有参数列表,可能就会写成:^{printf("Blocks Demo! ")};


          Block还可以申明变量,Block变量一样可以用typedef来定义成新的类型,这种做法下和函数指针真的非常非常类似,仅仅是将*换成了^。举个例子:

          int (^blk)(int) = ^int (int count) {return count+;};

          熟悉C语言的人对这个都会比较熟悉。这里有一个要说明,上面的赋值语句右侧可以省略掉返回类型(猜测是这部分信息编译器已经可以确定,所以不再是必须提供的了)。这样,上面的语句也可以写成;

           int (^blk)(int) = ^(int count) {return count+;};

          如果使用typedef,就可以更清晰一点:

          typedef int (^blk_t)(int);

          blk_t blk =  ^(int count) {return count+;};


    3. 截获自动变量值

          我们说Block是带自动变量的匿名函数,匿名函数现在已经知道了,下面就要看看“自动变量”了。Block可以访问在它之前申明的变量,但也有它特殊的地方,先看一个例子:

    int main(int argc, const char * argv[])
    {
        int val = 1;
        void (^blk)(void) = ^{printf("val=%d
    ", val);};
        
        val = 2;
        blk();
        return 0;
    }
    

          在这里,运行结果是val=1。请注意,虽然这个时候val的值已经变成了2,但Block里面仍然是1,也就是说,Block在定义时相当于对val这个变量照了张相,然后一直自己使用这张相片,不管val本身何去何从。


          这个特性可以带来很大的便利(记下了定义时的上下文),有时是我们所需要的;但一不小心也很容易错,所以使用时需要注意。另外需要说明的是,Block里面不能改变val这个变量的值,如果你试图改变,编译器会报错,换句话说,Block里面,val就是只读的,而且值就是定义时的那个。


          虽然记住上下文是个很棒的功能,但是有时我们需要外部上下文变化时,Block的内容也跟随改变或者要修改自动变量的值,这个就需要用到__block关键词了。继续上代码:

    int main(int argc, const char * argv[])
    {
        __block int val = 1;
        void (^blk)(void) = ^{printf("val=%d
    ", val);};
        
        val = 2;
        blk();
        return 0;
    }

          这段代码和上一段的区别仅仅是多了__block的声明,但运行结果就是val=2了,也就是说,Block能跟踪val的变化了。


          这时,Block里面也可以改变val的值了,就是说,用了__block之后,val对于Block不再是只读的了,而是和自己定义的变量一样了。

          在一个Block里面,往往两种变量都需要有,具体怎么使用,就看具体的情况了。


    4. Block的使用

          我总是觉得任何一种技术的出现总是用来解决某个问题的,也决定了在何种情况下使用该技术。Block应该如何使用呢?这是仁者见仁,智者见智的问题了,我接触最多的是在GCD里面。

          个人的感觉这个东东主要用在回调里面,比如:网络连接成功后我应该把某个按钮激活之类的,Block使用起来简洁明快,如鱼得水。GCD实际上也是给出了系统的回调,所以就特别适合Block大显身手。


    5. 其他

          Block当然还有其他的一些内容,比如可以作为函数参数来传递,比如当自动变量是ObjC的对象时,虽然不能修改,但可以调用对象的方法,再比如,C语言的数组不能作为自动变量等等。但这些都不是Block主要的内容,最重要的还是灵活的使用。

  • 相关阅读:
    NULL、nil、Nil、NSNull的区别
    URL中有中文字符,转码方法
    iOS极光推送 点击推送消息跳转页面
    iOS中响应者链条-触摸事件
    WKWebKit基础
    iOS开发之详解正则表达式
    iOS中正则表达式的三种使用方式
    VS下载Github的项目引用报错
    RabbitMQ环境搭建
    ASP.NET Core之NLog使用
  • 原文地址:https://www.cnblogs.com/huluo666/p/3645901.html
Copyright © 2020-2023  润新知