23

[self anyFunction]を__weakオブジェクトなしのブロックで渡すことは可能ですか?[self anyFunction]を__weakオブジェクトなしのブロック(iOS 5 + ARC)

例として、これは、システムフレームワークから有効なコードである:

[UIView animateWithDuration:0.8 animations:^{ 
      //Do animationStuff 
     } completion:^(BOOL finished) { 
      [self anyFunction]; 
}]; 

警告なしに完了ブロックに[self anyFunction]を渡すことができます。しかし、完了ブロックを使用して独自のメソッドを作成すると、次の警告が発生します。このブロックで 'self'を強くキャプチャすると、保持サイクルが発生する可能性があります。

実用的な解決策は非常に簡単です(iOS 5 + ARC)。

__weak MyClass *weakSelf = self; 

、あなたが呼び出す必要があり、完了ブロックで:

[weakSelf anyFunction]; 

しかし、戻って私の質問には:__weakを使用できるのは、システムのフレームワークのAPIで必要がないのはなぜブロックを宣言するまで警告を表示せずにselfを使用してください。また、ブロック内に__weakオブジェクトを必要とせずにメソッドを実装する方法は?

ありがとうございました。

答えて

53

エラーをスローするブロックは、ブロックがブロックをキャプチャしたものです。オブジェクトは、そのブロックを保持し、ブロックは、それが目的だ保持するための例

[object performBlock:^{ 
    [object performSomeAction]; // Will raise a warning 
}]; 

又は

[self performBlock:^{ 
    [self doSomething]; // Will raise a warning 
}]; 

しかし

[self performBlock:^{ 
    [object doSomething]; // <-- No problem here 
}]; 

ため。したがって、どちらの場合も、ブロックを実行するオブジェクトはブロックを所有し、ブロックもオブジェクトを所有します。だからあなたはループを持っています。メモリがリークしていることを意味します。

あなたが指定した例では、クラスメソッドがあります。 UIViewクラスではなく、UIViewクラスのブロックを呼び出しています。クラスにはメモリは関連付けられていません。おそらくコントローラからこの関数を呼び出しているので、self参照はブロックによって保持されていますが、selfはブロックを保持していないのでループはありません。

ブロック内で使用されているすべてのオブジェクトが弱く参照される必要はなく、保持サイクルを引き起こすオブジェクトだけでなく、気づいたこともあります。

+1

ありがとうございます、私の質問が明らかになりました。 私の場合、ブロックを所有するオブジェクトは 'ivar'なので、' self 'の '__weak'オブジェクトを使う必要があります。しかし、ブロックが使われている関数でオブジェクトを宣言すると、 'self'は自分自身の' __weak'オブジェクトなしで渡すことができます。 これは意味があります。再度、感謝します。 – andreschneider

+1

私が見つけたのは[self.ivar performBlock:^ {[self doSomething]; }];コンパイラの警告が表示され、[self performBlock:^ {[self doSomething]; }];コンパイラの警告は発生しません。 –

+0

かもしれない[self performBlock:^ {[self doSomething];}];は、[self performBlock:^ {[self doSomething];自己= nil;}]; – dklt

14

ARCの有無にかかわらずコンパイルする必要のあるコードでは、私は次のことを行います...機能的には、既にリストしたものと同じですが、__weakを回避します保持の解除サイクルを回避します:

// 
// FOR NON-ARC PROJECTS 
// 
__block __typeof__(self) bself = self; 
[someObject doThingWithBlock:^(id result){ 
    if (!bself) 
     return; 
    bself.thingWhich = result; 
}]; 

/// 
// FOR ARC PROJECTS 
// 
__weak MyClass *bself = self; 
[someObject doThingWithBlock:^(id result){ 
    if (!bself) 
     return; 
    bself.thingWhich = result; 
}]; 
+1

ARCの場合、これは保持サイクルにつながる可能性があります。 ( '__block'セマンティクスがオブジェクトを保持するように変更されました) –

+0

これは正しいです。 __weak MyClass * bself = selfを使用しています。 –

+0

アークの例と、非同期ブロックのエラー処理を追加しました。 –

関連する問題