Block在iOS平常開發中極其常見,你們應該幾乎都使用過,比較熟悉它的用法,並且知道Block可能引發循環引用,今天來聊聊Block,以及Block形成內存泄露的根本緣由。git
首先,Block和普通實例同樣是是一個對象,他有本身的isa指針。
它就是一個裏面存儲了指向定義代碼塊的函數指針和block外部上下文變量信息的結構體。經過斷點咱們看到block的isa指針,以下圖:github
咱們發現block的類型實際上是不一樣的,這是爲何接下來咱們看看Block到底有哪些類型。bash
咱們經過實際例子看看的各類類型的block函數
- (void)NSMallocBlock {
int tempInt = 1;
void (^block)(void) = ^ {
NSLog(@"----------%d----------\n\n",tempInt);
};
block();
[self printBlockSuperClass:block];
}
複製代碼
結果:NSMallocBlock -> __NSMallocBlock -> NSBlock -> NSObjectui
- (void)NSStaticBlock {
int tempInt = 1;
__weak void (^block)(void) = ^ {
NSLog(@"----------%d----------\n\n",tempInt);
};
block();
[self printBlockSuperClass:block];
}
複製代碼
結果:NSStackBlock -> __NSStackBlock -> NSBlock -> NSObjectatom
- (void)NSGlobalBlock {
void (^block)(int a) = ^ (int a){
NSLog(@"----------%d----------\n\n",a);
};
block(1);
[self printBlockSuperClass:block];
}
複製代碼
結果:NSGlobalBlock -> __NSGlobalBlock -> NSBlock -> NSObjectspa
咱們發現:指針
__weak
修飾時block爲__NSStackBlock,存儲在棧區。爲了驗證咱們定義了三中關鍵字的block,分別有storng、weak、copy修飾:code
@property (nonatomic, strong) TestBlock strongBlock;
@property (nonatomic, weak) TestBlock weakBlock;
@property (nonatomic, copy) TestBlock copyBlock;
複製代碼
驗證方法以下:orm
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的類型,咱們能夠得出以下結論:
__NSGlobalBlock__
__NSGlobalBlock__
(全局區)__NSMallocBlock__
(堆區);weak修飾的block是__NSStackBlock__
(棧區)有普通外部變量的block是在棧區建立的,當有copy和strong修飾符修飾的時,會把block從棧移到堆區。
ARC下使用copy和strong關鍵字修飾block是同樣的。