美文网首页ZJ_iOS面试转载学习准备
Block与函数指针有什么区别

Block与函数指针有什么区别

作者: 洲洲哥 | 来源:发表于2017-01-22 10:14 被阅读904次

    本文首发地址
    Block就是一个代码块,但是它的神奇之处在于在内联(inline)执行的时候(这和C++很像)还可以传递参数。同时block本身也可以被作为参数在方法和函数间传递,这就给予了block无限的可能。

    第一个区别,函数指针是对一个函数地址的引用,这个函数在编译的时候就已经确定了。而block是一个函数对象,是在程序运行过程中产生的。在一个作用域中生成的block对象分配在栈(stack)上,和其他所有分配在栈上的对象一样,离开这个作用域,就不存在了。
    Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。

    看看Block他的定义

    struct Block_descriptor {
        unsigned long int reserved;
        unsigned long int size;
        void (*copy)(void *dst, void *src);
        void (*dispose)(void *);
    };
    
    
    struct Block_layout {
        void *isa;
        int flags;
        int reserved; 
        void (*invoke)(void *, ...);
        struct Block_descriptor *descriptor;
        /* Imported variables. */
    };
    
    

    Block实体形式如下:

    ^(传入参数列){行为主体};
    

    Block实体开头是“^”,接着是由小括号所包起来的参数列(比如 int a, int b, int c),行为主体由大括号包起来,专有名字叫做block literal。行为主体可以用return回传值,类型会被compiler自动辨别。如果没有参数列要写成:

    ^(void)。
    

    例如下面的一个例子:

    ^(int a){return a*a;};  
    

    这是代表Block会回传输入值的平方值(int a 就是参数列, return a*a; 就是行为主体)。记得行为主体里最后要加“;”,因为是叙述,而整个{}最后也要加“;”,因为Block是物件实体。

    在ios开发中,blocks是对象,它封装了一段代码,这段代码可以在任何时候执行。Blocks可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似,但是有区别:blocks是inline的,并且它对局部变量是只读的。

    Block的定义:

         int (^myBlock) (int a,int b) = ^(int a,int b){  
           return a+b;  
       };  
    

    定义了一个名为myBlock的blocks对象,它带有两个int参数,返回int。等式右边就是blocks的具体实现,是不是有点像方法的定义?
    Blocks可以访问局部变量,但是不能修改。比如下面的代码就会报编译错

    int num = 0;  
        //使用block   
        int (^myBlock) (int a,int b) = ^(int a,int b){  
            num = a+b;  
            return num;  
        };  
    

    如果要修改就要加关键字:_block (注意,是两个下划线"")

    __block int num = 0;  
        //使用block   
        int (^myBlock) (int a,int b) = ^(int a,int b){  
            num = a+b;  
            return num;  
        };  
    

    作为函数的参数,blocks某种意义上替代了回调函数或者delegate。当函数调用了,假设某个事件触发,这时blocks里的内容就会运行。这样有利于代码的整合和阅读,你不需要到处去实现委托方法了。

    有下图说明

    定义结构体运行时.jpg

    定义完block之后,其实是创建了一个函数,在创建结构体的时候把函数的指针一起传给了block,所以之后可以拿出来调用。

    调用外部变量-值传递-不修改外部变量

    Block调用外部变量.jpg

    定义block的时候,变量a的值就传递到了block结构体中,仅仅是值传递,所以在block中修改a是不会影响到外面的a变量的。

    调用外部变量-改变外部变量

    __block前缀

    64cc2bc2a19782e1eb5ff5c11fa2d126_b.jpg

    这里就不直接传递a的值了,而是把a的地址传过去了,所以在block内部便可以修改到外面的变量了。

    总结

    1:如果有面试官问说,函数指针就是block,或者block就是函数指针。你就可以站起来给他说“你个low货”,然后甩一下你的头发,要回你的简历,打道回府

    2:函数指针是Block的一部分。为什么这样说,如果你用Block,就有一个变量的使用,循环引用等等部分。

    3:
    根据isa指针,block一共有3种类型的block
    _NSConcreteGlobalBlock 全局静态
    _NSConcreteStackBlock 保存在栈中,出函数作用域就销毁
    _NSConcreteMallocBlock 保存在堆中,retainCount == 0销毁
    而ARC和MRC中,还略有不同

    如有问题可添加我的QQ:1290925041
    还可添加QQ群:234812704(洲洲哥学院)
    欢迎各位一块学习,提高逼格!
    也可以添加洲洲哥的微信公众号

    更多消息

    更多信iOS开发信息 请以关注洲洲哥 的微信公众号,不定期有干货推送:

    这里写图片描述

    相关文章

      网友评论

        本文标题:Block与函数指针有什么区别

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