2013-08-10 10 views

答えて

8

readonly copyなり、答えはYesです。

外部ブロックは非同期にディスパッチされ、ランタイムはこのブロックのヒープ上にコピーを作成します。下に示すように、Block Implementation Specification - Clang 3.4 Documentationに記述されているように、内部ブロックのインポートされた変数もヒープにコピーされます。

OPの例では、「ブロック参照のインポートされたconstコピー」があります。

私は仕様の例を使用しています:

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

仕様はcopy_helperdispose_helper機能が必要とされていると述べている:

copy_helper機能は、両方の既存のスタックベースのポインタを渡されます新しいヒープ・バージョンへのポインタを返し、ランタイムにコールバックして、ブロック内のインポートされたフィールドに対して実際にコピー操作を実行する必要があります。

仕様の次のコード例は、解読が難しい(実際には、外側のブロックがヒープにコピーされたときに何が起こるかについて実際には不足しています)。とにかく、内部ブロックのインポートされた変数が(再帰的に)外部ブロックの生の記憶域にコピーされることを仕様が示しているように見えます。

ヒープ上に外部ブロックがコピーされると、内部ブロックのインポートされた変数が最終的にヒープ上にも存在するように見えます。

これは直感的に意味があります。

私はこれを実証する小さなテストプログラムを作った: (あなたはデバッグし、表面の下で何が起こっているか把握するために分解を調べなければならない)。(ローカルおよびインポート変数のアドレスによって示されるように)ブロックは、メインスレッド上で実行される

Stack: &x: 0x7fff5fbff868 
Stack: &x: 0x7fff5fbff864 
------- on main thread ------- 
&y0: 0x7fff5fbff70c 
&y1: 0x7fff5fbff708 
&x0: 0x1001081e0 
&x1: 0x1001081e4 
&y2: 0x7fff5fbff76c 
&y3: 0x7fff5fbff768 
&x0: 0x10010a588 
&x1: 0x10010a58c 
------- on thread 2 ------- 
&y0: 0x1000e5d9c 
&y1: 0x1000e5d98 
&x0: 0x1001081e0 
&x1: 0x1001081e4 
&y2: 0x1000e5dfc 
&y3: 0x1000e5df8 
&x0: 0x10010a588 
&x1: 0x10010a58c 
&y4: 0x1000e5e6c 
&y5: 0x1000e5e68 
&x0: 0x10010a5e8 
&x1: 0x10010a5ec 

は、それがスタックに住んで次のよう

#import <Foundation/Foundation.h> 


void foo(int param) 
{ 
    int x0 = param; 
    int x1 = param + 1; 
    void (^existingBlock)(void) = ^{ 
     int y0 = x0; 
     int y1 = x1; 
     printf("&y0: %p\n", &y0); 
     printf("&y1: %p\n", &y1); 
     printf("&x0: %p\n", &x0); 
     printf("&x1: %p\n", &x1); 
    }; 

    void (^vv)(void) = ^{ 
     int y2 = x0; 
     int y3 = x1; 
     existingBlock(); 
     printf("&y2: %p\n", &y2); 
     printf("&y3: %p\n", &y3); 
     printf("&x0: %p\n", &x0); 
     printf("&x1: %p\n", &x1); 
    }; 

    printf("Stack: &x: %p\n", &x0); 
    printf("Stack: &x: %p\n", &x1); 

    printf("------- on main thread -------\n"); 
    vv(); 

    dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
     printf("------- on thread 2 -------\n"); 
     assert(vv); 
     sleep(1); 
     int y4 = x0; 
     int y5 = x1; 
     vv(); 
     printf("&y4: %p\n", &y4); 
     printf("&y5: %p\n", &y5); 
     printf("&x0: %p\n", &x0); 
     printf("&x1: %p\n", &x1); 
    }); 
} 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 

     foo(1); 
     sleep(2); 
    } 
    return 0; 
} 

出力されます。 dispatch_asyncによって実行されると、ランタイムはブロックのローカル変数とインポートされた変数のアドレスからわかるように、内部ブロックを含むブロックをコピーしました。

ブロックvvをヒープにコピーするために、copy_helper_block関数でブレークポイントを設定することができます。

enter image description here

0

blockは、普通のオブジェクトと同じように別のブロックにキャッチされているため、ed(1セクタごとにコピーされません)です。async_blockブロックのコピーは、ブロックオブジェクトを送信した結果、ブロックをコピーしたオーバーライドretainメソッドを呼び出した[block retain]メッセージです。 Apple docsdispatch_async上から

+1

この情報はどこから入手しましたか?ブロックを保持すると何ができますか? –

+0

ブロックは 'NSObject'から継承しています(両方ともAppleの_NSBlock'クラスとGNUstep'GSBlock'クラスの両方ですが、どちらもプライベートですが、例外として、Core-Coundationに似たCベースのアプローチを採用しています)あなたのNSArrayとNSStringのように別のブロックで捕まえられたときに 'objc_retain()' edを取得しました –

+0

@Gabriele Petronella iOS 6.0とMac OS X 10.8以来、Maxthonはブロックが "Objects"であると言っても間違いありません。 ARCはそれらをオブジェクトオブジェクトポインタとして管理します。しかし、ブロックは自動的にコピーされます。この例では、Mac OS X 10.8またはiOS 6とARCが有効な場合でも、ヒープにシフトするために、ブロック 'ブロック 'を明示的にコピーする必要があります。さもなければ、 'block'がスタックに残り、非同期に呼び出されたブロック' async_block'がクラッシュします。 – CouchDeveloper

5

:だから

ブロック

The block to submit to the target dispatch queue. This function performs Block_copy and Block_release on behalf of callers. This parameter cannot be NULL.

は、async_blockがコピーされます。

this discussionパー

block(あなたの例ではasync_blockの内側)、私は信じてasync_block

関連する問題