Objective-C的Block實質與實現探究 part-5

Block截獲對象的情況

</br>

typedef void (^blk_t)(id);

blk_t blk;

{
    id array = [[NSMutableArray alloc] init];
    blk = [^(id obj) {
        
        [array addObject: obj];

        NSlog(@"array count = %ld", [array count]);

    } copy];
}

blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);

輸出結果:

array count = 1
array count = 2
array count = 3

代碼分析:在Block語法中使用array變量,因此array會被在棧上的Block所截獲,接著Block執(zhí)行了copy方法,Block和array被同時復制到堆上。所以我們才能夠在array超出作用域范圍而繼續(xù)使用它,此時使用的是被復制到堆上的array

轉換成C++代碼:

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0 *Desc;
    id __strong array;

    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, id __strong _array, int flags=0) : array(_array) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
}

static void __main_block_func_0(struct __main_block_impl_0 *cself, id obj) {
    id __strong array = __cself->array;
    
    [array addObject: obj];

    NSLog(@"array count = %ld", [array count]);
}

static void __main_block_copy_0(struct __main_block_impl_0 *dst, struct __main_block_impl_0 *src) {
    _Block_object_assign(&dst->array, src->array, BLOCK_FIELD_IS_OBJECT);
}

static void __main_block_dispose_0(struct __main_block_impl_0 *src) {
    _Block_object_dispose(src->array, BLOCK_FIELD_IS_OBJECT);
}

static struct __main_block_desc_0 {
    unsigned long reserved;
    unsigned long Block_size;
    void (*copy)(struct __main_block_impl_0 *, struct __main_block_impl_0 *);
    void (*dispose)(struct __main_block_impl_0 *);
} __main_block_desc_0_DATA = {
    0,
    sizeof(struct __main_block_impl_0),
    __main_block_copy_0,
    __main_block_dispose_0  
};


blk_t blk;

{
    id __strong array = [[NSMutableArray alloc] init];
    
    blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, array, 0x22000000);
    blk = [blk copy];
}

(*blk->impl.FuncPtr)(blk, [[NSObject alloc] init]);
(*blk->impl.FuncPtr)(blk, [[NSObject alloc] init]);
(*blk->impl.FuncPtr)(blk, [[NSObject alloc] init]);

可以看出,Block截獲對象和使用__block變量時的C++代碼十分相似。
array被Block截獲后,變成了Block結構體中的id __strong array成員變量。但是Objective-C中,C語言結構體不能含有__strong修飾符的變量。因為編譯器不知道應何時進行C語言結構體的初始化和廢棄操作,不能很好地管理內存。但是Objective-C的運行時庫卻能夠做到,所以即使Block結構體中有__strong修飾符的變量也可以恰當初始化和廢棄。

</br>

對比__block變量和截獲對象兩種情況的copy和dispose函數差異如下:


《Objective-C高級編程 iOS與OS X多線程和內存管理 》表2-7

截獲對象也算是截獲自動變量的一種,為什么截獲自動變量時,不需要copy和dispose函數呢?
其實也是有的,只不過沒有顯示出來。
</br>

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容