block普通引用
默认情况下,在block中访问外部变量是通过复制一个变量来操作的,既可以读,但是写操作不对原变量生效,下面通过代码来举证
NSString *a = @"testa"; NSLog(@"block前,a在堆中的地址%p,a在栈中的地址%p",a,&a); void(^testBlock)(void) = ^(void){ NSLog(@"block内,a在堆中的地址%p,a在栈中的地址%p",a,&a); }; NSLog(@"block后,a在堆中的地址%p,a在栈中的地址%p",a,&a); testBlock();
可以看出变量在堆中的地址其实是一直不变的,在栈中的地址,在block外是不变的,block内重新开辟了一个空间来存放。
那么来计算下两个地址变化
block前,a指向堆中的地址0x1000ec0b0,a在栈中的地址0x16fd19f58
block后,a指向堆中的地址0x1000ec0b0,a在栈中的地址0x16fd19f58
block内,a指向堆中的地址0x1000ec0b0,a在栈中的地址0x17404e0c0
十六进制的0x16fd19f58、0x17404e0c0转换为十进制数为,6170976088、6241444032。两者相差5546832956字节,再转换为MB为5289.8mb。已知IOS中一个进程的栈区内存只有1M,Mac也只有8M(等有空找官方文档求证下),又因为堆地址要小于栈地址,所以在block内调用变量,在不使用__block的情况下,是在堆中新建了一个变量地址指向原变量,block作用域结束则销毁,不影响原变量。
我们都知道:Block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。在block内调用变量,在不使用__block的情况下,是在堆中新建了一个变量地址指向原变量,block作用域结束则销毁,不影响原变量。
__block关键字
由前所知,通过__block修饰,block内部不仅仅可以对外部变量进行读操作,也可以进行写操作了,那这是为什么呢?同样用代码研究两者区别
__block NSString *a = @"testa"; NSLog(@"block前,a指向堆中的地址%p,a在栈中的地址%p&