前言
對于大多數(shù)iOS開發(fā)人員來說映跟,Block應該并不陌生,iOS4.0已開始支持Block拗小,在編程過程中,Block被Objective-C看成是對象樱哼,它封裝了一段代碼哀九,這段代碼可以在任何時候執(zhí)行剿配。Block可以作為函數(shù)參數(shù)或者函數(shù)的返回值,而其本身又可以帶輸入?yún)?shù)或返回值阅束。它是對C語言的擴展呼胚,用來實現(xiàn)匿名函數(shù)的特性。
Block的使用很像函數(shù)指針息裸,不過與函數(shù)最大的不同是:Block可以訪問函數(shù)以外蝇更、詞法作用域以內(nèi)的外部變量的值。
Block的特殊特性方便了開發(fā)人員的使用呼盆,但是Block的內(nèi)存需要開發(fā)人員自己管理年扩,錯誤的內(nèi)存管理會造成循環(huán)引用內(nèi)存泄露,或者內(nèi)存因為提前釋放造成崩潰访圃。
因此厨幻,Block的內(nèi)存管理是很重要的,本文將主要討論Block使用過程中的內(nèi)存管理問題腿时。
開發(fā)環(huán)境
- Xcode 9正式版
- ARC
- 真機調(diào)試 iPhone 7 Plus 11.0.1
- MacBook Pro 10.13
創(chuàng)建代碼如下:
//局部變量
- (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);
}
1.png
打印結(jié)果:
2.png
//靜態(tài)變量
- (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);
}
3.png
打印結(jié)果:
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);
}
5.png
打印結(jié)果:
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);
}
7.png
打印結(jié)果:
8.png
總結(jié)
- block中的變量是靜態(tài)或者全局類型時况脆,在block中該變量的內(nèi)存地址沒有發(fā)生改變。由于靜態(tài)變量和全局變量其地址是固定的批糟,因此block在定義的時候并沒有復制該變量的值格了,而是直接從其所在內(nèi)存中讀出。
- block中的變量是局部類型時徽鼎,在block中它的地址都發(fā)生了變化盛末,block在定義的時候拷貝了它(開辟了新的內(nèi)存空間),它在block中是作為常量使用的纬傲,其值不受外面的影響满败。
- block中的變量是__block類型時,在block中它的地址都發(fā)生了變化叹括,但是blockVar的值受到外界影響算墨,
這是因為blockVar在定義變量本身的時候是位于stack上的,而在定義block的時候汁雷,該變量并不是被復制了一份净嘀,而是編譯器將其轉(zhuǎn)移到了heap上,這個地方其實變量是被復制了一份的侠讯,并且作為生成的新的結(jié)構(gòu)體的一個成員變量挖藏。這個是更深層次的東西,等研究關于__block的原理的東西的時候會有相關介紹厢漩。
參考相關資料
iOS開發(fā)總結(jié)-Block(二)
Block源碼解析和深入理解
深入研究Block捕獲外部變量和__block實現(xiàn)原理