关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获

翻了很多文章,发现关于Swift闭包关于上下文变量捕获这块,都没有说的很详细,或者Swift2这样的老版本已经不适用了,问了GPT也是和自己实验的结果不一样,记录下来。

一:OC的block

首先,回顾一下OC中的block。
block对局部变量基本数据类型的捕获,是在创建时捕获了值,并保存副本在自己的结构体中,修改也是修改副本,不会影响到原本的值。
例子:

typedef void (^MyBlock)(void);

- (MyBlock)createBlock {
    int number = 10;
    MyBlock block = ^{
        NSLog(@"Captured value: %d", number);
    };
    number = 20;
    return block;
}

- (void)executeBlock {
    MyBlock myBlock = [self createBlock];
    myBlock(); 
}

最后输出是:

Captured value: 10

二:__block修饰符

如果希望block内部修改的值是原本的值,或者希望block捕获的值后面还会变化,需要对原本的变量添加__block修饰符。

typedef void (^MyBlock)(void);

- (MyBlock)createBlock {
    __block int number = 10;
    MyBlock block = ^{
        NSLog(@"Captured value: %d", number);
    };
    number = 20;
    return block;
}

- (void)executeBlock {
    MyBlock myBlock = [self createBlock];
    myBlock(); 
}

最后输出是:

Captured value: 20

三:Swift闭包

那Swift闭包对局部基本数据类型的变量的捕获是怎样的呢?Swift中没有__block修饰符,是不是就没法做到block那样的功能了呢?
答案是否定的,例子:

var i = 0
let closure = {
	print("\(i)")
}
i += 1
print("\(i)")
closure()
print("\(i)")

输出结果是什么呢?
第一个输出是1,很好理解。
第二个输出是闭包里的i,输出多少呢?
第三个输出是1,也好理解。
看答案:
关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获_第1张图片
闭包内输出是1 ,这好像和OC中block是不一样的?接着往下看。

顺便,很无奈的是,GPT给的答案也是错误的:

关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获_第2张图片

那么,看上去和OC中捕获__block修饰符的int是一样的?继续尝试:

var i = 0
let closure = {
    print("\(i)")
    i += 1
}
i += 1
print("\(i)")
closure()
print("\(i)")

输出结果是什么呢?
第一个输出是1,很好理解。
第二个输出是闭包里的i,是1,刚才已经看到了。
第三个输出输出多少呢?
看答案:
关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获_第3张图片
答案是2。说明闭包内修改的值,也会反应到闭包外部。

GPT给的答案也是错误的:
关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获_第4张图片

再看一个例子:

var i = 0
let closure = {
    print("\(i)")
}
i += 1
closure()
i += 1
closure()
i += 1
closure()

输出会是什么呢?
关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获_第5张图片
所以这几个例子都证明了,闭包对变量进行捕获,是将变量复制到了堆上,之后不论是闭包内,还是闭包外,操作的值,都是堆上的这个值,闭包对这个值强持有。

捕获值的本质是将变量存储到堆上。

1、一个闭包能够从上下文捕获已经定义的常量和变量,并且能够在其函数体内引用和修改这些值,即使这些定义的常量和变量的原作用域不存在;
2、修改捕获值实际是修改堆区中的value值;
3、当每次重新执行当前函数时,都会重新创建内存空间。

四:捕获列表

那么怎么做到,在定义时就确定捕获的值呢?就像block那样,没有__block修饰符的int?
使用捕获列表 [] in
关于Swift中闭包和OC中block对局部变量基本数据类型值的捕获_第6张图片
很容易理解,不再赘述。

你可能感兴趣的:(swift,iOS,swift,开发语言,ios)