objective-c - block 保留命名约定的循环?

标签 objective-c automatic-ref-counting clang

我很惊讶地发现以下行为......

@interface Foo : NSObject

- (void)addBar:(id)aBar withCompletion:(void(^)(void))completion;

@end

@interface AwesomeClass : NSObject

@property (strong, nonatomic) Foo *foo;

- (void)doSomethingWithBar:(id)bar;

@end

@implementation AwesomeClass

- (void)doSomethingWithBar:(id)bar
{
    [self.foo addBar:bar withCompletion:^{
        NSLog(@"%@", self.foo);
    }];
}

在 Xcode 4.6.1 中,我在 -doSomethingWithBar: 的实现中收到警告,“在此 block 中强烈捕获‘self’可能会导致保留周期。”

但是,如果我将方法 -addBar:withCompletion:name 重构为 -setupBar:withCompletion:,此警告就会消失。看来我对此感到惊讶说明我在 Objective-C 命名约定方面的知识存在差距!

最佳答案

代码

[self.foo someMethod:bar withCompletion:^{
    NSLog(@"%@", self.foo);
}];

通常不会创建保留循环。如果someMethod:withCompletion:只是调用 block 并返回,根本没有保留周期。 (-[NSArray enumerateObjectsUsingBlock:] 是一个例子。)

仅当 someMethod:withCompletion: “记住”稍后要执行的 block ,可能存在保留循环。因此 clang 使用启发式方法来确定它是否是将 block 存储到 Foo 的属性中的“setter-like”方法。稍后执行。

-set<Key>-add<Key>是键值编码中的访问器模式,用于设置属性或向(对多)关系添加值,而这正是 clang 检查的内容。

这可以在 Clang source code 中看到:

/// Check for a keyword selector that starts with the word 'add' or
/// 'set'.
static bool isSetterLikeSelector(Selector sel) {
  if (sel.isUnarySelector()) return false;

  StringRef str = sel.getNameForSlot(0);
  while (!str.empty() && str.front() == '_') str = str.substr(1);
  if (str.startswith("set"))
    str = str.substr(3);
  else if (str.startswith("add")) {
    // Specially whitelist 'addOperationWithBlock:'.
    if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock"))
      return false;
    str = str.substr(3);
  }
  else
    return false;

  if (str.empty()) return true;
  return !islower(str.front());
}

这里调用:

/// Check a message send to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
  // Only check instance methods whose selector looks like a setter.
  if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector()))
    return;

  /*
   * rest omitted
   */

}

你的 setupBar方法被视为“setter-like”方法,因为“set”后面没有跟大写字母。

关于objective-c - block 保留命名约定的循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15535899/

相关文章:

android - 可分配-是否支持-fno-objc-arc

objective-c - 在 FreeBSD 上使用 Objective-C 开发 Web 应用程序

Clang 的 ASan 不检测悬空指针的使用

objective-c - 如何解决这个错误?找不到实例方法 '-attributesOfItemAtPath:eror:'(返回类型默认为 'id')

iphone - iPhone 的自动完成搜索示例

iphone - 如何从 UIWebview 中删除选择?

macos - 如何在 Mac 上使用尖括号将 C 库安装为 <mylib.h>

objective-c - 是什么 |和 << 是什么意思?

objective-c - NSPointerArray 奇怪的压缩

ios - 局部变量默认为强还是弱?