【问题标题】:Idiom to hide `self` in Objective C blocks?在Objective C块中隐藏“self”的成语?
【发布时间】:2014-03-19 16:01:48
【问题描述】:

当我有一个 Objective C 实例创建一个需要引用该实例的块时,我经常通过一个不会使实例保持活动并产生保留循环的弱指针来执行此操作,如下所示:

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

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

【问题讨论】:

  • 你会收到一个警告......这有帮助吗?
  • 最新版本的 Xcode + ARC 将检测块中的强引用循环并给你一个警告。
  • 警告很有帮助,谢谢。我有一个解决方案,我会发布。它并不完美,但可能会引发更好的解决方案。
  • 编译器警告能否转为错误?
  • 当然。您应该始终将所有编译器警告转为错误。

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


【解决方案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();
  }
}

我不相信这是值得的努力。有编译器警告可能就足够了,它们可能会变成错误?

【讨论】:

  • 有趣的解决方案:)
猜你喜欢
  • 2015-12-20
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
  • 2010-09-17
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
相关资源
最近更新 更多