又见block(一):block是什么?

block的原理是一道分水岭,区分中高级程序的试金石,一般的大公司,他可能不会问你内存管理,甚至多线程编程问题也简单的一笔带过,但是block一定会仔细问。可惜的是平时只知使用,对其原理与实质没有深究,因此数次面试倒在这道坎上,真是心有不甘,这次好好理理关于block的前因后果,以供后续随手翻阅查证。

block的定义:带有自动变量(局部变量)的匿名函数

想要说明什么是匿名函数,先来了解下什么是函数以及函数指针

  • 函数:函数是C语言程序中的重要组成部分,不同函数调用的组合实现程序的各个功能。
    格式如下:
    returnType FuncName(Paramter List){
        //FuncBody
    }

returnType:函数返回值
FuncName:函数名
Paramter List:参数列表
FuncBody:函数体
一个简单的函数如下:

    int funcSum (int count) {
        return count + 10;
    }

定义了一个名为funcSum的函数,有一个int类型的形参,返回值是int类型
函数调用如下:

    int result = funcSum(18);
  • 函数指针:除了直接调用函数之外,我们还可以定义一个函数指针来指向这个函数地址,通过调用函数指针进而调用指向的函数,函数指针的定义如下:
    returnType (*FuncPointer)(Paramter List)

继续上面定义的funcSum函数,现在定一个函数指针指向这个函数

    int*funcPointer)(int)= &funcSum;

调用函数指针方式如下:

    int result = (*funcPointer)(18);

通过函数指针可以来调用函数,但是在给函数指针赋值的过程中,依然用到了函数名,因此在C语言中要想调用函数,无论是直接调用还是通过函数指针来调用都无法绕过函数名。

但是OC中的block,就可以使用不带函数名称的函数,即匿名函数,被看着是C语言的扩充功能。

在了解什么是匿名函数后,再来说说“带有自动变量(局部变量)”是什么意思?
变量的类型以及存储位置

  • 全局变量:全局静态区
  • 全局静态变量:全局静态区
  • 局部静态变量:栈
  • 局部变量:栈
    内存分布
    局部变量:包括静态局部变量都是存在栈中的,超过作用域后就会被销毁
    全局变量:包括全局静态变量,既不是存在栈中,也不是存在堆中,而是存放在“全局区/静态区”,占用静态的存储单元

block做为匿名函数,不但能访问全局变量,更重要的是拥有捕获函数外局部变量的功能,一般情况下,block中访问一个外部局部变量,block会持用它的临时状态,自动捕获变量值,捕获后修改外部的局部变量不会影响block内部捕获的状态
比较经典的例子:

    int val = 23;
    void (^block) (void) = ^{
        NSLog(@"val = %d",val);
    };
    val = 2;
    block();

代码输出为:val = 23,不是2
block在定义实现时,就会对它捕获的外部局部变量进行一次只读拷贝,然后在block中使用该只读拷贝,即外部局部变量的副本,所以block外部修改局部变量,对其内部的副本无影响,就是说block捕获的是局部变量的瞬时值
那么这种情况下能否在block内对局部变量val值进行修改呢?尝试报错截图如下:
这里写图片描述
根据错误提示,我们修改代码如下

    __block int val = 23;
    void (^block) (void) = ^{
        NSLog(@"val = %d",val);
    };
    val = 2;
    block();

代码输出结果为:val = 2,并且此时可以在block中修改外部的局部变量值


为什么在局部变量定义前加__block就能在block中修改捕获的局部变量值了,后面再继续分析,本节完,待续……

参考文章

猜你喜欢

转载自blog.csdn.net/GeekLee609/article/details/82250664