Objective-C Block方法

來源:互聯網
上載者:User

標籤:

block 有什麼意義,特點等等,這些東西,實在是太複雜了,這裡只是簡單的總結一下block的記憶體管理。而且也僅僅限於objective-C的部分

Block memory

block 的記憶體管理,應該是最頭疼的地方,就用這個來自WWDC的例子來解釋一下吧。

當程式運行到這裡時,stack 空間中有 shared 變數和 captured 變數。

這裡可以看出,__block 變數開始是處於stack上的。

當程式運行到這裡時,stack 空間中有 shared 變數,captured 變數和block1。

這裡可以看出,block 類型的變數開始時也是處在stack上的。

當程式運行到這裡時,stack 空間中有 shared 變數,captured 變數和block1。

這裡值得注意的就是當我們直接修改stack 上的captured變數時,block1中的captured變數仍然是原來的數值10。事實上,從const 我們就可以看出,block1中的captured變數是不能被修改的而且是從stack原有變數的一個const 拷貝。在block1中訪問的captured變數是const拷貝的,也就是說block1中captured = 10,而不是原有的stack上的值 20。當然,在block1中,我們也不能修改captured變數。

 Copy block

block在一開始是處在stack上的,這是為了考慮到效率的原因,但是,有時候是需要block的生命週期長於一開始的stack,這時,我們就通過copy block 來將block複製到heap。

當程式執行完 block2 = [block1 copy];時,__block 類型變數shared,被複製到了heap中,很顯然,shared變數需要被block和block2共用(當然還有stack也要共用),而block2被移動到heap中,很可能生命週期會長於stack,所以,shared也被複製到了heap中。而block2中的captured 也被複製到了heap中。

當程式執行完 block3 = [block2 copy];時, 我們看到的是,block2 和block3 其實指向的是同一片記憶體空間。事實上,block的資料結構中,儲存了引用計數,而對於copy到heap中的block 再copy時,行為同普通對象retain一樣,會使引用計數+1。那麼如果我們對[block retain]會如何呢? 實際上什麼都沒有發生,至少在現在的runtime版本下。因為retain中,不僅有引用計數+1在,而且retain的傳回值,必須同返回調用對象的地址一樣,而block的地址是可能變化的(stack or heap),所以,這裡retain的行為幾乎是被忽略掉的。

當heap中的block變數先於stack被銷毀時,如調用 [block2 release]; [block3 release];,heap中的block2,block3 由於引用計數為0 而被銷毀,而 __block 變數shared則還在heap中,因為stack還要使用,block1 也要使用。

當heap中的block變數晚於stack時,顯然,stack 被清除,function中也啥都沒了。

最後,當block2 和block3 都被release之後。則恢複到最初狀態

 block details

當我們寫出一個Block literal expression

^ { printf("hello world\n"); }
事實上,編譯器為我們產生了如下結構
struct __block_literal_1 {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(struct __block_literal_1 *);
    struct __block_descriptor_1 *descriptor;
};void __block_invoke_1(struct __block_literal_1 *_block) {
    printf("hello world\n");
}static struct __block_descriptor_1 {
    unsigned long int reserved;
    unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1)}; 當Block literal expression 使用時 __block_literal_1 則會被初始化為:struct __block_literal_1 _block_literal = {
    &_NSConcreteStackBlock,
    (1<<29), <uninitialized>,
    __block_invoke_1,
    &__block_descriptor_1
   };

下一個例子

int x = 10;
void (^vv)(void) = ^{printf("x is %d\n", x);};
x = 11;
vv();

編譯器會產生如下結構
struct __block_literal_2{
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_2 *);
    struct __block_descriptor_2 *descriptor;
    const int x;
};

void __block_invoke_2(struct __block_literal_2 *_block){
    printf("x is %d\n", _block->x);
}

void struct __block_descriptor_2{
    unsigned long int reserved;
    unsigned long int block_size;
}__block_descriptor_2 = {0, sizeof(struct __block_literal_2)};

struct __block_literal_2 __block_literal_2 = {
    &NSConcreteStackBlock,
    (1<<29),
    __block_invoke_2,
    &__block_descriptor_2,
    x
};

block中使用的普通變數(int, char *)匯入是const copy。普通對象則會retain。__block 類型變數則什麼不做,只是儲存一個指標,全域變數也只是儲存一個簡單的指標。

當然,block 可能也會嵌套block,那麼又會是什麼樣子?其實不複雜,複雜的只是增加了複製函數,和釋放函數,這一點很像C++的拷貝建構函式,在必要時產生。

void (^existingBlock)(void) = …;

void (^vv)(void) = ^{existingBlock();};

vv();

struct __block_literal_3{
    ...;//esisting block
};

struct __block_literal_4{
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_4 *);
    struct __block_literal_3 *const existingBlock;
};

void __block_invoke_4(struct __block_literal_3 *__block) {
   __block->existingBlock->invoke(__block->existingBlock);
}

void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
     //_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
     _Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}

void __block_dispose_4(struct __block_literal_4 *src) {
     // was _Block_destroy
     _Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}

static struct __block_descriptor_4 {
    unsigned long int reserved;
    unsigned long int Block_size;
    void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
    void (*dispose_helper)(struct __block_literal_4 *);
} __block_descriptor_4 = {
    0,
    sizeof(struct __block_literal_4),
    __block_copy_4,
    __block_dispose_4,
};

初始化

  struct __block_literal_4 _block_literal = {
    &_NSConcreteStackBlock,
    (1<<25)|(1<<29), <uninitialized>
    __block_invoke_4,
    & __block_descriptor_4
        existingBlock,
   };

 

__block storage variables

__block  變數是一種很特殊的資料類型,有自己的特有的資料結構

struct _block_byref_xxxx {
    void *isa;
    struct _block_byref_xxxx *forwarding;
    int flags;   //refcount;
    int size;
    // helper functions called via Block_copy() and Block_release()
    void (*byref_keep)(void  *dst, void *src); //需要時被產生
    void (*byref_dispose)(void *);//需要時被產生
    typeof(marked_variable) marked_variable;
};

看看__block 類型變數的使用

int __block i = 10;
i = 11;

struct _block_byref_i {
    void *isa;
    struct _block_byref_i *forwarding;
    int flags;   //refcount;
    int size;
    int captured_i;
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };

i.forwarding->captured_i = 11;

 

顯然,當block中增加了__block 類型變數之後,嵌套block 的拷貝函數也會增加對__block 變數的複製。

__block void (voidBlock)(void) = blockA;
voidBlock = blockB;

struct _block_byref_voidBlock {
    void *isa;
    struct _block_byref_voidBlock *forwarding;
    int flags;   //refcount;
    int size;
    void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
    void (*byref_dispose)(struct _block_byref_voidBlock *);
    void (^captured_voidBlock)(void);
};

void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
    //_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
    _Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
}

void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
    //_Block_destroy(param->captured_voidBlock, 0);
    _Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}

struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
      .byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
      .captured_voidBlock=blockA )};

voidBlock.forwarding->captured_voidBlock = blockB;

 

block中,引入了__block 會是什麼情況

int __block i = 2;
functioncall(^{ i = 10; });
struct _block_byref_i {
    void *isa;  // set to NULL
    struct _block_byref_voidBlock *forwarding;
    int flags;   //refcount;
    int size;
    void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
    void (*byref_dispose)(struct _block_byref_i *);
    int captured_i;
};


struct __block_literal_5 {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(struct __block_literal_5 *);
    struct __block_descriptor_5 *descriptor;
    struct _block_byref_i *i_holder;
};

void __block_invoke_5(struct __block_literal_5 *_block) {
   _block->i_holder->forwarding->captured_i = 10;
}

void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
     _Block_object_assign(&dst->i_holder, src->i_holder, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}

void __block_dispose_5(struct __block_literal_5 *src) {
     _Block_object_dispose(src->i_holder, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}

static struct __block_descriptor_5 {
    unsigned long int reserved;
    unsigned long int Block_size;
    void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
    void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };


struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
struct __block_literal_5 _block_literal = {
    &_NSConcreteStackBlock,
    (1<<25)|(1<<29), <uninitialized>,
    __block_invoke_5,
    &__block_descriptor_5,
        2,
   };

 以上內容摘自http://www.cnblogs.com/studentdeng/archive/2012/02/03/2336863.html 不會開機的男孩所寫的, 對於block 認為這個寫的很詳細了,所以直接借鑒了!

Objective-C Block方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.