block系列1-block使用

1.使用Blocks


(1)block概念

Blocks是帶有自動變了(局部變量)的匿名函數。其寫法遵循BN范式

^ 返回值類型 參數列表 表達式

返回值類型可省略,參數列表亦可省略。可以定一個Blocks變量來獲得匿名函數的使用權

int (^blk)(int) = ^(int count){return count+1};

我們可以作為參數傳遞Blocks變量,也可以返回Blocks類型變量,也可以使用typedef定義更方便使用Blocks變量

void func(int (^blk)(int)){}

int (^func())(int){
    return ^(int count){return count+1};
}

typedef int (^blc_t)(int);
  • block的代碼是內聯(lián)的,效率高于函數調用
  • block對于外部變量默認是只讀屬性,要在block內修改外部變量需要添加_block關鍵字修飾
  • block被Objective-C看成是對象處理

block會捕獲在其定義時的變量值,變量修改后并不會影響block中使用的變量。

{
    int a = 10;
    int (^blc)(int) = int ^(int count){return count+a;};
    a++;
    NSLog(@"%@",blc(5));//打印15,而不是16
}

變量的復制關系如下

block外變量引用,默認是復制到block內的readonly變量

[站外圖片上傳中...(image-7c89d1-1524555790555)]

對于用__ block修飾的外部變量引用,block復制其引用地址來實現訪問

[站外圖片上傳中...(image-a85bf0-1524555790555)]

(2)block常見用法:

  1. 局部位置聲明一個Block型的變量

    return_type (^blockName)(var_type) = ^return_type (var_type varName) {
        // ...
    };
    blockName(var);
    
  2. @interface聲明Block型屬性

    @property(nonatomic, copy)return_type (^blockName) (var_type);
    
  3. Block型作為形參

    - (void)yourMethod:(return_type (^)(var_type))blockName;
    
  4. 內聯(lián)用法,定義后立即調用,不常用

    ^return_type (var_type varName)
    {
        //...
    }(var);
    
  5. 遞歸調用

    使用__block避免循環(huán)引用問題。

    __block return_type (^blockName)(var_type) = [^return_type (var_type varName)
    {
        if (returnCondition)
        {
            blockName = nil;
            return;
        }
        // ...
        // 【遞歸調用】
        blockName(varName);
    } copy];
    
    【初次調用】
    blockName(varValue);
    
  6. 作為返回值

    - (return_type(^)(var_type))methodName
    {
        return ^return_type(var_type param) {
            // ...
        };
    }
    

    ?

2.block原理


(1)數據結構定義

block的數據結構定義如下

[站外圖片上傳中...(image-894ad2-1524555790555)]

結構體定義如下

#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {
    unsigned long int reserved;
    unsigned long int size;
};
struct Block_layout {
    void *isa;
    volatile int flags; // contains ref count
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 *descriptor;
    // imported variables
};
//Block-private.h

對于每個參數解釋如下

  1. isa: 對象指針
  2. flags: 記錄block的一些附加信息,包括引用計數
  3. reserved: 保留變量。
  4. invoke: 函數指針,指向block函數實現地址。
  5. descriptor:附加信息描述
//falgs bit位描述如下
enum {
    BLOCK_DEALLOCATING =      (0x0001),  // runtime
    BLOCK_REFCOUNT_MASK =     (0xfffe),  // runtime
    BLOCK_NEEDS_FREE =        (1 << 24), // runtime
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compiler
    BLOCK_HAS_CTOR =          (1 << 26), // compiler: helpers have C++ code
    BLOCK_IS_GC =             (1 << 27), // runtime
    BLOCK_IS_GLOBAL =         (1 << 28), // compiler
    BLOCK_USE_STRET =         (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
    BLOCK_HAS_SIGNATURE  =    (1 << 30)  // compiler
};

從枚舉變量的定義可以看出flags的bit位作用,第0位表示釋放內存標志,1-23bit作為引用計數值,24-31略過。

在OC中有三種block

  1. _NSConcreteGlobalBlock 全局的靜態(tài) block,不會訪問任何外部變量。
  2. _NSConcreteStackBlock 保存在棧中的 block,當函數返回時會被銷毀,ARC下不適用。
  3. _NSConcreteMallocBlock 保存在堆中的 block,當引用計數為 0 時會被銷毀。

下篇文章講解不同block的實現方式

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容