web-dev-qa-db-ja.com

常にブロック内で自己への弱い参照を使用する必要があります。

ブロック内での自己の使用に困惑しています。Appleのドキュメントをいくつか調べましたが、それでも正しい答えが見つかりません。

一部の人々は常にブロック内でウィークセルフを使用すると言いますが、コピーするブロックではウィークセルフを使用すると言いますが、常に使用する必要はありません。

サンプル1:

self.handler = ^(id response, NSError *error)
{
    self.newresponse = response; //use weak self here
};  

サンプル2:

弱い自己を使用します。

__weak myViewController *weakSelf = self;

[UIView animateWithDuration:interval delay:0.0 options:curve animations:^
{
    [weakSelf.view.superview setTransform:CGAffineTransformMakeTranslation(0, -106)];
    //in above is it use of weak is neassary 
}
completion:^(BOOL finished)
{

}];

弱い自己なし;

__weak myViewController *weakSelf = self;

[UIView animateWithDuration:interval delay:0.0 options:curve animations:^
{
    [myViewController.view.superview setTransform:CGAffineTransformMakeTranslation(0, -106)];

}
completion:^(BOOL finished)
{

}];

上記のサンプルで正しいのは…? ** ARCを使用しています

43
ShivaPrasad

selfがブロックの参照を保持する場合は、selfへの弱い参照のみを使用する必要があります。

あなたの例では、ブロックへの参照をselfに保持せず、UIView animateWithDuration:でインラインでブロックを使用しているだけなので、__weak myViewController *weakSelf = self;を使用する必要はありません。

これはなぜですか?ブロックは、ブロックを使用するクラスから使用する変数への強い参照を保持するためです。これにはselfが含まれます。これで、クラスインスタンス自体がブロックへの強い参照を保持し、ブロックがクラスインスタンスへの強い参照を保持する場合、保持サイクルが発生し、メモリリークが発生します。

76
WDUK

@WDUKの答えを示すコードは次のとおりです。

typedef void (^SimpleBlock)();

@interface ObjectThatRetainsBlock : NSObject
@property(nonatomic, strong) SimpleBlock block;
@end

@implementation ObjectThatRetainsBlock

- (instancetype)init {
  self = [super init];
  if (self) {
    self.block = ^{ NSLog(@"Running block in %@", self); };
    self.block();
  }
  return self;
}

- (void)dealloc {
  NSLog(@"ObjectThatRetainsBlock is deallocated.");
}

@end

@interface ObjectThatDoesNotRetainBlock : NSObject
@end

@implementation ObjectThatDoesNotRetainBlock

- (instancetype)init {
  self = [super init];
  if (self) {
    SimpleBlock block = ^{ NSLog(@"Running block in %@", self); };
    block();
  }
  return self;
}

- (void)dealloc {
  NSLog(@"ObjectThatDoesNotRetainBlock is deallocated.");
}

@end

- (void)test {
  ObjectThatRetainsBlock *objectThatRetainsBlock =
      [[ObjectThatRetainsBlock alloc] init];
  ObjectThatDoesNotRetainBlock *objectThatDoesNotRetainBlock = 
      [[ObjectThatDoesNotRetainBlock alloc] init];
}

testメソッドは以下を出力します:

Running block in <ObjectThatRetainsBlock: 0x7f95f3335e50>
Running block in <ObjectThatDoesNotRetainBlock: 0x7f95f3335c50>
ObjectThatDoesNotRetainBlock is deallocated.

initObjectThatDoesNotRetainBlockメソッドで、blockをivarとして作成しますが、blockがスコープ外になると、それへの参照。

testメソッドでは、2つのオブジェクトがスコープから外れたときに、objectThatDoesNotRetainBlockが保持サイクルの一部ではないため、割り当てが解除されていることに注意してください。

一方、objectThatRetainsBlockは保持サイクルの一部であるため、割り当て解除されません。メソッド呼び出しの範囲を超えてブロックを保持します。

別の説明が必要な場合は、 この答え を参照してください。

10
Rose Perrone