成语隐藏Objective C块中的`self`?

时间:2014-03-19 16:01:49

标签: objective-c objective-c-blocks self weak-references

当我有一个Objective C实例创建一个需要引用该实例的块时,我经常通过一个弱指针来实现,该指针不会保持实例存活并产生一个保留周期,如下所示:

__weak MyType *const weakSelf = self;
void (^aBlock)() = ^(){
  // Do things with weakSelf instead of self.
}

我想要一个成语,阻止我在街区中利用强大的自我。理想情况下,在使用成语时,如果我尝试在块中使用self而不是weakSelf,则会出现编译错误。运行时错误也可以。

1 个答案:

答案 0 :(得分:1)

我有一个解决方案,我不是特别喜欢,但它可能会引发更好的答案。我会留下未答复的,希望有更好的解决方案到达。

这是一种方法:

// Here's a method definition…
-(void) aMethod
{
  // Want to create a block in which its impossible to refer to strong "self".
  // Begin a new scope to do this in.
  {
    // Within this scope, cover the existing "self" with a weak variant.
    __weak STWeatherTableViewController const *weakSelf = self;
    __weak STWeatherTableViewController const *self = weakSelf;

    // Sadly it's _not_ possible to simply do:
    //   __weak STWeatherTableViewController const *self = self;
    // … it gives a warning about initialisation of a variable form its own
    // uninitialised value, which makes sense, though you might hope the
    // compiler would work out what's going on.

    // Make a block that captures the covered self and does something with it.
    void (^exampleBlock)() = ^(){ [self lineHeight]; };
    exampleBlock();
  }

  // Now, back in the scope of the original method, "self" is non weak
  // again.
  [self doSomething];
}

我想,如果你真的非常关心这个问题,你可以使用一个宏。它至少会抽象出这个想法,并使代码易于查找和注意:

#define WEAKEN_SELF(classType) \
__weak classType const *weakSelf = self; \
__weak classType const *self = weakSelf

甚至:

#define WEAKEN_SELF(classType) \
__weak classType const *weakSelfTemporary##__LINE__ = self; __weak classType const *self = weakSelfTemporary##__LINE__;

您可以这样使用它:

-(void) testMethod
{
  // You still need that scope or you cover the original "self".
  {
    WEAKEN_SELF(STWeatherTableViewController)
    void (^exampleBlock)() = ^(){ [self someMethodOrOther]; };
    exampleBlock();
  }
}

我不相信这是值得的。编译器警告可能已经足够好了,它们可能会被转为错误吗?