Block使用中のいくつかの疑問解答


原文の住所:http://jessex.me/?p=181
本論文は主にBlockの外部変数とBlock自身のメモリ管理について説明する.
先にblock変数を定義し、後の例として使用します.
typedef void(^BlockCC)(void);
BlockCC _block;
1、blockで外部変数を参照する
blockでは外部変数を直接使用することができます.
 
int number = 1;
_block = ^(){
    NSLog(@"number %d", number);
};
実際にblockが生成されるとnumberは定数変数としてブロックに符号化されます.ブロック中のnumber値は、以下のコードでは変わりません.
 
int number = 1;
_block = ^(){
    NSLog(@"number %d", number);
};
number = 2;
_block();
出力の値は2ではなく1です.その理由は上記の通りです.
blockで外部変数の値を変更しようとすると、エラーが発生します.この問題に対する解決策は導入である.block識別子blockの内部で修正が必要な変数を_u u u u u u_と表記します.block scope.変更後のコードは以下の通りです.
 
__block int number = 1;
_block = ^(){
    number++;
    NSLog(@"number %d", number);
};
この時、実はblock外部のnumberとblock内部のnumberは同じ値を指しています.さっきの外部に戻ってblockを変えた例は、その出力結果は1ではなく2です.興味のある人は自分で例を書いてみてください.
 
 
2、block自身のメモリ管理
block自体は対象のようにretainとreleaseができます.しかし、ブロックは作成時にスタックに割り当てられています.彼自身のドメインは作成時のスコックに属しています.作成時のスコックを外から呼び出したら、プログラムが崩壊します.例えば次の例です.私はview did loadでblockを作成しました.
 
- (void)viewDidLoad
{
    [superviewDidLoad];

    int number = 1;
    _block = ^(){

    NSLog(@"number %d", number);
};
}
このブロックは、ボタンのイベントで呼び出された.
 
 
- (IBAction)testDidClick:(id)sender {
    _block();
}
この時ボタンを押したらプログラムが崩壊します.この問題を解決する方法はブロックを作成する時にcopyを呼び出す必要があります.copyはブロックをスタックからスタックに移動させます.他のところでこのブロックを使用できます.修正コードは下記の通りです.
 
_block = ^(){
    NSLog(@"number %d", number);
};

_block = [_blockcopy];
同じように、特に注意すべき点はブロックを集合類に置く時に、直接に生成したブロックを集合類に入れると、他のところでblockが使えないので、ブロックをcopyしなければなりません.でもコードはちょっと変に見えます.
[array addObject:[[^{
    NSLog(@"hello!");
} copy] autorelease]];
 
3、循環参照
この点は実は最初の時点での小さな派生です.block内部でメンバー変数を使う場合、例えば
 
@interface ViewController : UIViewController
{
    NSString *_string;
}
@end
block作成中:
_block = ^(){
    NSLog(@"string %@", _string);
};
ここの_stringがかなりあってself->_ストリングスblockは内部の対象に対して一回retainを行います.つまり、selfは一度retainされます.selfが解放される時、blockが釈放されてからやっとselfが解放されますが、blockのリリースはまたselfのdeallocの中で釈放されるのを待つ必要があります.これにより循環参照が形成され、メモリが漏れてしまう.修正案は新しく作った_u u_u uです.block scopeの局所変数は、selfを与え、block内部ではこの局所変数を用いて値を取る.なぜならblockマークの変数は自動的にretainされません.
 
__block ViewController *controller = self;
_block = ^(){
    NSLog(@"string %@", controller->_string);
};
まずここに書きます.基本的にはblockを使う時にぶつかる問題です.より詳細な説明が必要です.「Adancend Mac OS X Programeming」という本を見て、紹介します.