web-dev-qa-db-ja.com

配列へのブロックの格納

Objective-Cでは、ブロックはオブジェクトと見なされることを知っているので、ブロックを配列に格納できるかどうか疑問に思いました。これは問題を引き起こします、ブロックはファーストクラスのオブジェクトですか、それともオブジェクト間で渡すためにオブジェクトのように扱われるだけですか?それらがファーストクラスのオブジェクトである場合、それらは配列に格納できませんか?

50
noizetoys

編集:ARCの下では、あまり詳しく説明しなくても、他のオブジェクトと同様にコレクションにブロックを追加できます(説明を参照)。

元の回答には、興味深い技術的な詳細が含まれているため、そのまま残しておきます。


これは問題を引き起こします、ブロックはファーストクラスのオブジェクトですか、それともオブジェクト間で渡すためにオブジェクトのように扱われるだけですか?それらがファーストクラスのオブジェクトである場合、それらは配列に格納できませんか?

ブロックは、他のすべてのNSObjectとほとんど同じように動作するObjective-Cオブジェクトですが、いくつかの重要な違いがあります。

  • ブロックは常にコンパイラーによって生成されます。実行がブロック宣言を通過するとき、それらは実行時に効果的に「割り当て/初期化」されます。

  • ブロックは最初にスタックに作成されます。 Block_copy()またはcopyメソッドを使用して、ブロックを現在のスコープよりも長く存続させる場合は、ブロックをヒープに移動する必要があります(下記のARCポイントを参照)。

  • ブロックには、メモリ管理以外に呼び出し可能なAPIはありません。

  • ブロックをコレクションに入れるには、まずコピーする必要があります。 常に。 ARCを含む。 (コメントを参照してください。)そうしないと、スタックに割り当てられたブロックがautoreleasedになり、アプリが後でクラッシュするリスクがあります。

  • スタックベースのブロックをコピーすると、キャプチャされた状態もすべてコピーされます。ブロックの複数のコピーを作成する場合は、一度コピーしてからコピーする方が効率的です(ブロックを変更できないため、コピーをコピーすると保持数が増えるためです)。

  • ARCでは、メソッドまたは関数から「正常に機能する」ブロックを返します。それは自動的にヒープにコピーされ、戻りは事実上自動解放されたブロックになります(コンパイラーは特定の状況で自動解放を最適化する場合があります)。 ARCを使用しても、コレクションに貼り付ける前にブロックをコピーする必要があります。

ブロックの概要 といくつかの ヒントとコツ の両方を提供するいくつかのブログ投稿を書きました。面白いかもしれません。

そして、はい、辞書に追加することは非常に便利です。キーをコマンド名とするコマンドハンドラーとしてブロックを辞書にドロップするコードをいくつか書きました。とても便利な。

90
bbum

はい、ブロックは確かにオブジェクトであり、配列に入れることができます:

NSMutableArray *arr = [NSMutableArray new];
[arr addObject:^(){NSLog(@"my block");}];
void (^ myblock)() = [arr objectAtIndex:0];
myblock();

これにより、コンソールに「マイブロック」が配置されます。

39
Eduardo Scoz