//最近總是犯迷糊,關於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變量是受外界影響的,導致輸出結果為空。