前言
Block在iOS日常開發(fā)中極其常見,大家應(yīng)該幾乎都使用過,比較熟悉它的用法,而且知道Block可能引起循環(huán)引用,今天來聊聊Block,以及Block造成內(nèi)存泄露的根本原因。
Block是什么
首先,Block和普通實(shí)例一樣是是一個對象,他有自己的isa指針。
它就是一個里面存儲了指向定義代碼塊的函數(shù)指針和block外部上下文變量信息的結(jié)構(gòu)體。通過斷點(diǎn)我們看到block的isa指針,如下圖:
我們發(fā)現(xiàn)block的類型其實(shí)是不同的,這是為什么接下來我們看看Block到底有哪些類型。
Block的類型
我們通過實(shí)際例子看看的各種類型的block
- NSMallocBlock
- (void)NSMallocBlock {
int tempInt = 1;
void (^block)(void) = ^ {
NSLog(@"----------%d----------\n\n",tempInt);
};
block();
[self printBlockSuperClass:block];
}
結(jié)果:NSMallocBlock -> __NSMallocBlock -> NSBlock -> NSObject
- NSStaticBlock
- (void)NSStaticBlock {
int tempInt = 1;
__weak void (^block)(void) = ^ {
NSLog(@"----------%d----------\n\n",tempInt);
};
block();
[self printBlockSuperClass:block];
}
結(jié)果:NSStackBlock -> __NSStackBlock -> NSBlock -> NSObject
- NSGlobalBlock
- (void)NSGlobalBlock {
void (^block)(int a) = ^ (int a){
NSLog(@"----------%d----------\n\n",a);
};
block(1);
[self printBlockSuperClass:block];
}
結(jié)果:NSGlobalBlock -> __NSGlobalBlock -> NSBlock -> NSObject
我們發(fā)現(xiàn):
- 當(dāng)沒有外部變量時,block為__NSMallocBlock,它由開發(fā)者創(chuàng)建,存儲在堆內(nèi)存上。
- 當(dāng)有
__weak修飾時block為__NSStackBlock,存儲在棧區(qū)。 - 當(dāng)block有參數(shù)時(捕獲了外部變量時)block為__NSGlobalBlock,存儲在全局區(qū)。
屬性關(guān)鍵字和外部變量類型對Block內(nèi)存的影響
為了驗(yàn)證我們定義了三中關(guān)鍵字的block,分別有storng、weak、copy修飾:
@property (nonatomic, strong) TestBlock strongBlock;
@property (nonatomic, weak) TestBlock weakBlock;
@property (nonatomic, copy) TestBlock copyBlock;
驗(yàn)證方法如下:
int globalInt = 1000;//全局變量
static staticInt = 10000;//全局靜態(tài)變量
- (void)blockInMemory {
static tempStaticInt = 100000;//局部靜態(tài)變量
int normalInt = 20000;
_strongBlock = ^(int tempInt) {
NSLog(@"tempInt = %d", normalInt);
};
_weakBlock = ^(int tempInt) {
NSLog(@"tempInt = %d", normalInt);
};
_copyBlock = ^(int tempInt) {
NSLog(@"tempInt = %d", normalInt);
};
NSLog(@"\nstrongBlock:%@\n_weakBlock:%@\n_copyBlock:%@",object_getClass(_strongBlock),object_getClass(_weakBlock),object_getClass(_copyBlock));
}
分別打印不同變量類型(全局變量、全局靜態(tài)變量、局部靜態(tài)變量、局部變量)和屬性關(guān)鍵字下block的類型,我們可以得出如下結(jié)論:
- 沒有外部變量時,三種Block都是
__NSGlobalBlock__ - 有外部變量時,
2.1 外部變量時全局變量、全局靜態(tài)變量、局部靜態(tài)變量時:__NSGlobalBlock__(全局區(qū))
2.2 外部變量時普通外部變量:copy和strong修飾的Block是__NSMallocBlock__(堆區(qū));weak修飾的block是__NSStackBlock__(棧區(qū))
有普通外部變量的block是在棧區(qū)創(chuàng)建的,當(dāng)有copy和strong修飾符修飾的時,會把block從棧移到堆區(qū)。
ARC下使用copy和strong關(guān)鍵字修飾block是一樣的。
結(jié)語
本篇為Block系列的第一篇,由此,我們了解了三種不同類型Block,接下來會以源碼的方式深入了解block的底層實(shí)現(xiàn),我們下篇再見。
Demo工程