iOS开发总结-浅谈Block的内存管理

前言

对于大多数iOS开发人员来说,Block应该并不陌生,iOS4.0已开始支持Block,在编程过程中,Block被Objective-C看成是对象,它封装了一段代码,这段代码可以在任何时候执行。Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它是对C语言的扩展,用来实现匿名函数的特性。
Block的使用很像函数指针,不过与函数最大的不同是:Block可以访问函数以外、词法作用域以内的外部变量的值。
Block的特殊特性方便了开发人员的使用,但是Block的内存需要开发人员自己管理,错误的内存管理会造成循环引用内存泄露,或者内存因为提前释放造成崩溃。
因此,Block的内存管理是很重要的,本文将主要讨论Block使用过程中的内存管理问题。


开发环境
  • Xcode 9正式版
  • ARC
  • 真机调试 iPhone 7 Plus 11.0.1
  • MacBook Pro 10.13

创建代码如下:

//局部变量
- (void)localVar
{
    int localVar = 10;
    NSLog(@"localVar --%p",&localVar);
    sumBlock block1 = ^(int x,int y){
        NSLog(@"localVar --%p",&localVar);
        return localVar + x + y;
    };
    localVar = 0;
    int z = block1(1,2);
    NSLog(@"localVar -- z = %d",z);
}
iOS开发总结-浅谈Block的内存管理_第1张图片
1.png

打印结果:

2.png
//静态变量
- (void)staticVar
{
    static int staticVar = 10;
    NSLog(@"staticVar --%p",&staticVar);
    sumBlock block2 = ^(int x,int y){
        NSLog(@"staticVar --%p",&staticVar);
        return staticVar + x + y;
    };
    staticVar = 0;
    int z = block2(1,2);
    NSLog(@"staticVar -- z = %d",z);
}
iOS开发总结-浅谈Block的内存管理_第2张图片
3.png

打印结果:

4.png
//全局变量
- (void)globalVar
{
    NSLog(@"globalVar --%p", &globalVar);
    sumBlock block3 = ^(int x, int y) {
        NSLog(@"globalVar --%p", &globalVar);
        return globalVar + x + y;
    };
    globalVar = 0;
    int z = block3(1, 2);
    NSLog(@"globalVar -- z = %d", z);
}
iOS开发总结-浅谈Block的内存管理_第3张图片
5.png

打印结果:


6.png
//__block
- (void)blockVar
{
    __block int blockVar = 10;
    NSLog(@"blockVar --%p", &blockVar);
    sumBlock block4 = ^(int x, int y) {
        NSLog(@"blockVar --%p", &blockVar);
        return blockVar + x + y;
    };
    blockVar = 0;
    int z = block4(1, 2);
    NSLog(@"blockVar -- z - %d", z);
}
iOS开发总结-浅谈Block的内存管理_第4张图片
7.png

打印结果:


8.png
总结
  1. block中的变量是静态或者全局类型时,在block中该变量的内存地址没有发生改变。由于静态变量和全局变量其地址是固定的,因此block在定义的时候并没有复制该变量的值,而是直接从其所在内存中读出。
  2. block中的变量是局部类型时,在block中它的地址都发生了变化,block在定义的时候拷贝了它(开辟了新的内存空间),它在block中是作为常量使用的,其值不受外面的影响。
  3. block中的变量是__block类型时,在block中它的地址都发生了变化,但是blockVar的值受到外界影响,这是因为blockVar在定义变量本身的时候是位于stack上的,而在定义block的时候,该变量并不是被复制了一份,而是编译器将其转移到了heap上,这个地方其实变量是被复制了一份的,并且作为生成的新的结构体的一个成员变量。这个是更深层次的东西,等研究关于__block的原理的东西的时候会有相关介绍。

参考相关资料

iOS开发总结-Block(二)
Block源码解析和深入理解
深入研究Block捕获外部变量和__block实现原理

你可能感兴趣的:(iOS开发总结-浅谈Block的内存管理)