-1

こんにちは、objective-c でブロックを扱っています。構文とブロックの書き方を学習したところです。しかし、私は実行フローを理解していませんでした。実行の流れをグーグルで検索しましたが、見つかりません。

次のコードを使用しました:

@interface NSArray (Extended)
- (NSArray *)each:(void (^)(id))block;
@end

@implementation NSArray (Extended)
- (NSArray *)each:(void (^)(id object))block {
for(id mObject in self)
    block(mObject);
return self;
}
@end

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

  NSArray *array = [NSArray arrayWithObjects:@"Number one", @"Number two", nil];
  [array each:^(id object) {
     NSLog(@"obj: %@", object);
  }];

}
return 0;
}

Objective-C でのブロックの実行の流れを説明できる人はいますか?

4

3 に答える 3

5

もちろん。

  • main() が呼び出されます

  • 2 つの文字列を含むanarrayが割り当てられます

  • メソッドは配列で呼び出され、each:引数として単一のオブジェクトを取るブロックを渡します

  • メソッドは、ループeach:を使用して配列内のすべてのオブジェクトを反復処理しますfor()

    • メソッドに渡されたブロックはeach:、各オブジェクトに対して 1 回呼び出され、オブジェクトはブロックの引数になります。

    • ブロックは、オブジェクトを説明する行をログに記録します


ブロックは、コンパイル時にコードをキャプチャし、実行時に状態をキャプチャします。この場合、ブロックは状態をキャプチャしていません。このブロックは、呼び出されるたびに 1 行のログを出力する単純な C 関数のようなものです。

于 2013-05-03T16:26:50.513 に答える
3

あなたが物事をどのように説明したいのかわからない。これが私の試みです:

ブロックはコードの一部です。を使用してブロックを作成する^{}と、そのコードを変数に格納できます。あなたの場合(そしてほとんどの場合)、他の値と同様に、メソッドに引数としてすぐに渡されます。この例のブロックは、コードが実行されるときに値を指定する必要がある 1 つの引数を宣言します。変数object_in はいくつかのオブジェクトが含まれ、コードのブロックでそれを操作できます。

[array each:^(id object_in) {
    NSLog(@"object: %@", object_in);
}];

メソッド内で、コードは引数変数に格納されblock、ケースで名前が付けられます。次に、コードを実行します。これを行うには、ブロック引数として実数値のリストに括弧を追加します。現在object_out、いくつかの実際の値が含まれているため、 に渡されobject_inます。

- (NSArray *)each:(void (^)(id))block {
    for (id object_out in self) {
        block(object_out); // executes the code of block with given argument
    }
    return self;
}

NSLogこれで、配列内のすべてのオブジェクトでステートメントが実行されます。

関数ポインタと非常によく似ています。あなたがそれについて何か知っているなら、それはより簡単かもしれません.そうでない場合は、気にしないでください:)


したがって、引数によって値をブロックに渡すことができますが、値をブロックに取得する 2 番目の方法もあります。ローカル変数のキャプチャに関するものですが、例では使用されていません。あなたまたは他の誰かが私に説明してほしい場合は、お気軽にコメントしてください。


編集:ここでは、キャプチャされた変数について簡単に説明します。で囲まれたすべてのコード{}スコープなので、ブロックもスコープです。スコープはネストされており、その中で作成されたローカル変数は、制御フローがスコープを離れるまでのみ有効です。子スコープは、親スコープの変数を使用できます。

以下のコード例は、2 つの配列を反復処理します。1 つはfor-inループで、もう 1 つ-each:は質問のメソッドです。引数として渡されるブロックは少し異なります。親スコープから 1 つの変数を使用します (実際には、祖父母スコープからのものです)。このブロックが違うのはなぜですか?メソッドは、異なる値-each:を含むたびに複数回実行されます。stringつまり、ブロックの 3 つのインスタンスがそれぞれ独自のstring値で作成されます。

NSArray *strings = @[ @"A", @"B", @"C" ];
NSArray *numbers = @[ @1, @2, @3 ];

NSString *string = nil; // doing this to be more obvious
for (string in strings) {
    // string is simple local variable
    [numbers each:^(id number) {
        // number is argument
        NSLog(@"argument: %@, captured: %@", number, string);
    }];
}

出力:

argument: 1, captured: A
argument: 2, captured: A
argument: 3, captured: A
argument: 1, captured: B
argument: 2, captured: B
argument: 3, captured: B
argument: 1, captured: C
argument: 2, captured: C
argument: 3, captured: C

したがって、3 つのインスタンスすべてに共通のコードと、それぞれに異なる (異なる可能性がある) いくつかの変数があります。これでクラス/オブジェクトの関係を思い出すなら、あなたは正しいです。

引数はブロックの呼び出しごとに異なり (前のコード例に示されています)、キャプチャされた変数はインスタンスごとに異なります。^{ブロック定義( )のある行が実行されるたびに、新しいインスタンスが作成されます。

于 2013-05-03T17:17:51.147 に答える
1

ドキュメントから:

ブロック オブジェクトは、C レベルの構文およびランタイム機能です。これらは標準の C 関数に似ていますが、実行可能コードに加えて、自動 (スタック) またはマネージド (ヒープ) メモリへの変数バインディングも含まれる場合があります。したがって、ブロックは、実行時に動作に影響を与えるために使用できる一連の状態 (データ) を維持できます。

さらに明確にするために、このリンクを確認してください。

于 2013-05-03T09:44:56.460 に答える