web-dev-qa-db-ja.com

__blockおよび__weakの使用

私はこのスレッドを読みました: 「__ block」キーワードの意味は何ですか? これは__blockが使用されていますが、答えの1つについて混乱しています。 __blockは保持サイクルを回避するために使用されますが、その下のコメントは不確かです。

私はそれを次のように使用しています:

 self.someProperty = x; //where x is some object (id)
 __block __weak VP_User *this = self;

 //begin a callback-style block
     this.someProperty = nil;

両方を使用する必要がありますか__blockおよび__weak?これがこのように見えることで明白な問題はありますか?

27
Adam

__blockはストレージ修飾子です。変数をコピーするのではなく、ブロックで直接キャプチャする必要があることを指定します。これは、次の例のように、元の変数を変更する必要がある場合に役立ちます。

__block NSString *aString = @"Hey!"; 
void(^aBlock)() = ^{ aString = @"Hello!" }; // without __block you couldn't modify aString
NSLog(@"%@", aString); // Hey!
aBlock();
NSLog(@"%@", aString); // Hello!

ARCでは、これにより変数が自動的に保持されるため、ブロック実装内で安全に参照できます。前の例では、ブロックコンテキストでキャプチャされると、aStringretainメッセージが送信されます。

これは、変数が保持されずに参照されるMRC(手動参照カウント)では当てはまりません。

__weakとしてマークすると、変数は保持されないため、ブロックはそれを直接参照しますが、保持しません。これは、ブロックが変数よりも長く存続する場合、ガベージメモリを参照するため(そしてクラッシュする可能性が高いため)、潜在的に危険です。

clang doc の関連する段落を次に示します。

Objective-CおよびObjective-C++言語では、オブジェクトタイプの__weak変数に対して__block指定子を使用できます。 [...]この修飾子により、これらの変数は、送信されるメッセージを保持せずに保持されます。これは、ブロック(またはコピー)がこのオブジェクトの存続期間よりも長く存続する場合、故意にダングリングポインターにつながります。

最後に、__blockを使用して強い参照サイクル(別名保持サイクル)を回避できるという主張は、ARCコンテキストでは明らかに間違っています。 ARCでは__blockによって変数が強く参照されるため、実際にはその可能性が高くなります。

たとえばMRCでは、このコードは保持サイクルを中断します

__block typeof(self) blockSelf = self; //this would retain self in ARC!
[self methodThatTakesABlock:^ {
    [blockSelf doSomething];
}];

aRCで同じ結果を得るには、通常、

__weak typeof(self) weakSelf = self;
[self methodThatTakesABlock:^ {
    [weakSelf doSomething];
}];
60

ブロック内の変数値を変更する場合は、__blockを使用する必要があります。

例えば:

__block BOOL result = NO;
dispatch_sync(dispatch_get_main_queue(), ^{
  ...
  result = YES;
  ...
});

保持サイクルを回避する場合は、__weakを使用する必要があります。

例えば。:

__weak typeof(self) wself = self;
self.foobarCompletion = ^{
  ...
  wself.foo = YES;
  ...
};

必要に応じて組み合わせることができます。

14