前言
Block在iOS日常開發中極其常見,大家應該幾乎都使用過,比較熟悉它的用法,而且知道Block可能引起迴圈引用,今天來聊聊Block,以及Block造成記憶體洩露的根本原因。
Block是什麼
首先,Block和普通例項一樣是是一個物件,他有自己的isa指標。
它就是一個裡面儲存了指向定義程式碼塊的函式指標和block外部上下文變數資訊的結構體。通過斷點我們看到block的isa指標,如下圖:
我們發現block的型別其實是不同的,這是為什麼接下來我們看看Block到底有哪些型別。
Block的型別
我們通過實際例子看看的各種型別的block
- NSMallocBlock
- (void)NSMallocBlock {
int tempInt = 1;
void (^block)(void) = ^ {
NSLog(@"----------%d----------\n\n",tempInt);
};
block();
[self printBlockSuperClass:block];
}
複製程式碼
結果:NSMallocBlock -> __NSMallocBlock -> NSBlock -> NSObject
- NSStaticBlock
- (void)NSStaticBlock {
int tempInt = 1;
__weak void (^block)(void) = ^ {
NSLog(@"----------%d----------\n\n",tempInt);
};
block();
[self printBlockSuperClass:block];
}
複製程式碼
結果:NSStackBlock -> __NSStackBlock -> NSBlock -> NSObject
- NSGlobalBlock
- (void)NSGlobalBlock {
void (^block)(int a) = ^ (int a){
NSLog(@"----------%d----------\n\n",a);
};
block(1);
[self printBlockSuperClass:block];
}
複製程式碼
結果:NSGlobalBlock -> __NSGlobalBlock -> NSBlock -> NSObject
我們發現:
- 當沒有外部變數時,block為__NSMallocBlock,它由開發者建立,儲存在堆記憶體上。
- 當有
__weak
修飾時block為__NSStackBlock,儲存在棧區。 - 當block有引數時(捕獲了外部變數時)block為__NSGlobalBlock,儲存在全域性區。
屬性關鍵字和外部變數型別對Block記憶體的影響
為了驗證我們定義了三中關鍵字的block,分別有storng、weak、copy修飾:
@property (nonatomic, strong) TestBlock strongBlock;
@property (nonatomic, weak) TestBlock weakBlock;
@property (nonatomic, copy) TestBlock copyBlock;
複製程式碼
驗證方法如下:
int globalInt = 1000;//全域性變數
static staticInt = 10000;//全域性靜態變數
- (void)blockInMemory {
static tempStaticInt = 100000;//區域性靜態變數
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));
}
複製程式碼
分別列印不同變數型別(全域性變數、全域性靜態變數、區域性靜態變數、區域性變數)和屬性關鍵字下block的型別,我們可以得出如下結論:
- 沒有外部變數時,三種Block都是
__NSGlobalBlock__
- 有外部變數時,
2.1 外部變數時全域性變數、全域性靜態變數、區域性靜態變數時:__NSGlobalBlock__
(全域性區)
2.2 外部變數時普通外部變數:copy和strong修飾的Block是__NSMallocBlock__
(堆區);weak修飾的block是__NSStackBlock__
(棧區)
有普通外部變數的block是在棧區建立的,當有copy和strong修飾符修飾的時,會把block從棧移到堆區。
ARC下使用copy和strong關鍵字修飾block是一樣的。
結語
本篇為Block系列的第一篇,由此,我們瞭解了三種不同型別Block,接下來會以原始碼的方式深入瞭解block的底層實現,我們下篇再見。
Demo工程