11

Apple のドキュメントには次のように書かれています。ブロック リテラル (つまり、^{ ... }) は、ブロックを表すスタック ローカル データ構造のアドレスです。したがって、スタック ローカル データ構造のスコープは外側の複合ステートメントであるため、次の例に示すパターンは避ける必要があります。

void dontDoThis() {

    void (^blockArray[3])(void);  // an array of 3 block references

    for (int i = 0; i < 3; ++i) {

        blockArray[i] = ^{ printf("hello, %d\n", i); };

        // WRONG: The block literal scope is the "for" loop.
    }

    //for example I invoke the block here
    blockArray[1]();
  }


void dontDoThisEither() {

    void (^block)(void);

    int i = random():

    if (i > 1000) {

        block = ^{ printf("got i at: %d\n", i); };

        // WRONG: The block literal scope is the "then" clause.

    }

    // ...

  }

どのパターンを避けるべきかわかりません。たとえば、「if」または「for」ステートメントの後ろなど、ブロック定義と同じリテラルスコープを持つブロックを呼び出すことができたようです。説明を手伝っていただけませんか?

ここにリンクがあります https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1

4

2 に答える 2

9

ポインタとの類似性は次のとおりだと思います。

void foo() {
  int *block = NULL;
  {
    int a;
    block = &a;
  }
  // `block`, even though defined here, points to
  // an invalid memory address.
}

通常、ブロックリテラル自体は、それが定義されているブロックにのみ存在するため、そのブロックを離れると、リテラルは消え(a上記の例の変数のように)、ダングリングポインターが残ります。

このため、ブロックは通常、将来使用するためにヒープにコピーされます。非ARCコードの使用block_copyと友人。ヒープにコピーすると、ブロックが使用するすべての関連変数もキャプチャされます(保持サイクルが作成される可能性があります)。

実際には、これらすべては、ARC、プロパティ、およびクラスの使用によって完全に回避されます。クラスでプロパティを定義しcopy、それにブロックを割り当てるだけです。コンパイラにゲッター/セッターを生成させると、ブロックリテラルが自動的にヒープにコピーされます。

@interface Bla : NSObject
@property (nonatomic, copy) void (^blockProperty)(int i);
@endf

...

Bla *bla = [[Bla alloc] init];
{
  bla.blockProperty = ^(int i) { printf("%d", i); };
}
// bla.blockProperty now points to a heap copy of the block literal from above,
// so it's not dangling.
于 2012-11-28T00:07:20.960 に答える