Block的類型

前言

Block在iOS平常開發中極其常見,你們應該幾乎都使用過,比較熟悉它的用法,並且知道Block可能引發循環引用,今天來聊聊Block,以及Block形成內存泄露的根本緣由。git

Block是什麼

首先,Block和普通實例同樣是是一個對象,他有本身的isa指針。
它就是一個裏面存儲了指向定義代碼塊的函數指針和block外部上下文變量信息的結構體。經過斷點咱們看到block的isa指針,以下圖:github

isa

咱們發現block的類型實際上是不一樣的,這是爲何接下來咱們看看Block到底有哪些類型。bash

Block的類型

咱們經過實際例子看看的各類類型的block函數

  • NSMallocBlock
- (void)NSMallocBlock {
    int tempInt = 1;
    void (^block)(void) = ^ {
        NSLog(@"----------%d----------\n\n",tempInt);
    };
    block();
    [self printBlockSuperClass:block];
}
複製代碼

結果:NSMallocBlock -> __NSMallocBlock -> NSBlock -> NSObjectui

  • NSStaticBlock
- (void)NSStaticBlock {
    int tempInt = 1;
    __weak void (^block)(void) = ^ {
        NSLog(@"----------%d----------\n\n",tempInt);
    };
    block();
    
    [self printBlockSuperClass:block];
}
複製代碼

結果:NSStackBlock -> __NSStackBlock -> NSBlock -> NSObjectatom

  • NSGlobalBlock
- (void)NSGlobalBlock {
    void (^block)(int a) = ^ (int a){
        NSLog(@"----------%d----------\n\n",a);
    };
    block(1);
    
    [self printBlockSuperClass:block];
}
複製代碼

結果:NSGlobalBlock -> __NSGlobalBlock -> NSBlock -> NSObjectspa

咱們發現:指針

  1. 當沒有外部變量時,block爲__NSMallocBlock,它由開發者建立,存儲在堆內存上。
  2. 當有__weak修飾時block爲__NSStackBlock,存儲在棧區。
  3. 當block有參數時(捕獲了外部變量時)block爲__NSGlobalBlock,存儲在全局區。

屬性關鍵字和外部變量類型對Block內存的影響

爲了驗證咱們定義了三中關鍵字的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的類型,咱們能夠得出以下結論:

  1. 沒有外部變量時,三種Block都是 __NSGlobalBlock__
  2. 有外部變量時,
    2.1 外部變量時全局變量、全局靜態變量、局部靜態變量時:__NSGlobalBlock__(全局區)
    2.2 外部變量時普通外部變量:copy和strong修飾的Block是__NSMallocBlock__(堆區);weak修飾的block是__NSStackBlock__(棧區)

有普通外部變量的block是在棧區建立的,當有copy和strong修飾符修飾的時,會把block從棧移到堆區。

ARC下使用copy和strong關鍵字修飾block是同樣的。

Demo工程

相關文章
相關標籤/搜索