//最近总是犯迷糊,关于block对外部变量的引用,今天有时间就写了一下,加深自己的理解,巩固基础知识
1 #import <Foundation/Foundation.h> 2 int gNum = 100; 3 int main(int argc, const char * argv[]) { 4 @autoreleasepool { 5 static int sNum = 100; 6 __block int bNum = 100; 7 int lNum = 100; 8 int (^sum)(int, int) = ^(int a, int b) { 9 NSLog(@"%d %d %d %d",sNum,gNum,lNum,bNum); 10 sNum++; 11 bNum++; 12 gNum++; 13 return a + b + lNum + gNum + sNum + bNum ; 14 }; 15 sNum = 1; 16 bNum = 1; 17 gNum = 1; 18 lNum = 1; 19 20 NSLog(@"%d",sum(1,2)); 21 NSLog(@"%d",sNum); 22 NSLog(@"%d",bNum); 23 NSLog(@"%d",gNum); 24 NSLog(@"%d",lNum); 25 26 } 27 return 0; 28 }
打印结果
1 12:57:09.984 xxx[10180:2208151] 109 2 12:57:09.984 xxx[10180:2208151] 2 3 12:57:09.984 xxx[10180:2208151] 2 4 12:57:09.984 xxx[10180:2208151] 2 5 12:57:09.984 xxx[10180:2208151] 1
Block其实包含两个部分内容
1.Block执行的代码,这是在编译的时候已经生成好的;
2.一个包含Block执行时需要的所有变量值的数据结构。Block将使用到的,作用域附近的变量的值建立一份快照拷贝到栈上。
Block与函数另一个不同是,Block类似Objc的对象,可以使用自动释放池管理内存
3 Block对外部变量的存取管理
基本数据类型
1,局部变量
局部自动变量,在Block中只读。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值。
2, static修饰符的静态变量或全局变量
因为全局变量货静态变量在内存中的地址是固定的,Block在读取改变量值的时候是直接从其所在的内存读出的,获取daode 是最新值,而不是在定义时copy的常量。
3,__block修饰的变量
block变量,在被__block修饰的变量称作Block变量。基本类型的Block变量等小雨全局变量或静态变量。Block的使用很像函数指针,不过与函数最大的不同是:Block可以访问函数以外,词法作用域以内的外部变量的值。
二、对象类型
//本地对象
打印结果:
2018-03-17 13:44:25.848 test1[1332:79267] localObj adress-- 0xbff7ced4 2018-03-17 13:44:25.848 test1[1332:79267] localObj adress-- 0x7b63f8b4 2018-03-17 13:44:25.848 test1[1332:79267] localObj --<UILabel: 0x7c8337a0; frame = (0 0; 0 0);
//静态对象 - (void)staticObjTest { static UILabel *staticObj ; staticObj = [[UILabel alloc]init]; NSLog(@"staticObj adress --%p", & staticObj); void (^test)() = ^{ NSLog(@"staticObj adress --%p", & staticObj); NSLog(@"staticObj --%@",staticObj); }; staticObj = nil; test(); }
打印结果:
2018-03-17 13:44:25.917 test1[1332:79267] staticObjadress -- 0x85a48 2018-03-17 13:44:25.917 test1[1332:79267] staticObjadress -- 0x85a48 2018-03-17 13:44:25.917 test1[1332:79267] staticObj --(null)
//全局对象 - (void)globalObjTest { globalObj = [[UILabel alloc]init]; NSLog(@"staticObj adress --%p", & globalObj); void (^test)() = ^{ NSLog(@"globalObj adress --%p", & globalObj); NSLog(@"globalObj --%@",globalObj); }; globalObj = nil; test(); }
2018-03-17 13:44:25.917 test1[1332:79267] staticObjadress -- 0x85a4c 2018-03-17 13:44:25.917 test1[1332:79267] globalObjadress -- 0x85a4c 2018-03-17 13:44:25.917 test1[1332:79267] globalObj --(null)
//block对象 - (void)blockObjTest { __block UILabel *blockObj = [[UILabel alloc]init]; NSLog(@"blockObj adress --%p", & blockObj); void (^test)() = ^{ NSLog(@"blockObj adress --%p", & blockObj); NSLog(@"blockObj --%@",blockObj); }; blockObj = nil; test(); }
打印结果:
2018-03-17 13:44:25.917 test1[1332:79267] blockObj adress-- 0xbff7ced0 2018-03-17 13:44:25.918 test1[1332:79267] blockObj adress-- 0x7c835598 2018-03-17 13:44:25.918 test1[1332:79267] blockObj --(null)
总结:从测试结果可以看到
*对于静态对象变量和全局对象变量,其地址同样不是固定的。
*对于局部(本地)对象变量,定义block的时候同样复制了(指针)变量,其在block中是作为(指针)常量使用的,不会受外界影响。
*对于block对象变量,定义block的时候同样将变量从栈转移到了堆上,这一点用刚才的方法同样可以验证。因此block变量是受外界影响的,导致输出结果为空。