Avoiding the “capturing self strongly in this bloc

2019-03-11 06:57发布

every time I have to use a global var or property inside a block like this:

self.save = ^(){
  if (isItSaving == NO) {
      [self saveMyFile];
  }
};

I have to rewrite this like

BOOL *iis = isItSaving;
id myself = self;

self.save = ^(){
  if (iis == NO) {
      [myself saveMyFile];
  }
};

or Xcode will complain "capturing self strongly in this block is likely to lead to a retain cycle...

It complains even about BOOL variables?

Redeclaring everything before a block appears to be a lame solution.

Is this the correctly way? Is there an elegant way?

This stuff is ugly. I am using ARC.

3条回答
仙女界的扛把子
2楼-- · 2019-03-11 07:16

Use __unsafe_unretained typeof(self) weakSelf = self;

查看更多
别忘想泡老子
3楼-- · 2019-03-11 07:18

In addition to @NikolaiRuhe's response, in your example when declaring the properties

BOOL *iis = isItSaving;
id myself = self;

implies strong references, so use __weak self to prevent the retain cycle. Then you might wonder why you need to declare a __strong reference to weak self within the block, and that's to make sure it doesn't get released during the life of the block, otherwise weakSelf->isItSaving would break if self was released.

查看更多
贪生不怕死
4楼-- · 2019-03-11 07:32

The problem only occurs when referencing self from within the block, explicitly or implicitly. There's no warning emitted when accessing global variables.

In your case you probably accessed a (boolean) ivar. Accessing the ivar implicitly uses self, that's why the compiler is warning you (correctly) about a retain cycle.

The common way to fix the retain cycle is:

typeof(self) __weak weakSelf = self;

self.save = ^() {
    typeof(weakSelf) __strong strongSelf = weakSelf;
    if (strongSelf != nil && ! strongSelf->isItSaving) {
        [strongSelf saveMyFile];
    }
};

... and, yes, that's a bit of an ugly part of blocks.

查看更多
登录 后发表回答