Objective c 紧凑禁用自参考块的arc retain cycles警告

Objective c 紧凑禁用自参考块的arc retain cycles警告,objective-c,objective-c-blocks,clang,automatic-ref-counting,Objective C,Objective C Blocks,Clang,Automatic Ref Counting,我正在编写一个涉及事件处理的API,我希望能够为处理程序使用块。回调通常需要访问或修改self。在ARC模式下,Clang警告说,引用self的块可能会创建一个retain循环,这似乎是一个有用的警告,我希望在一般情况下继续 但是,对于API的这一部分,回调的生命周期和包含的对象是在外部维护的。我知道当对象应该被释放时,我可以打破这个循环 我可以使用#pragma clang diagnostic ignored“-Warc retain cycles”关闭每个文件的保留周期警告,但这会禁用整个

我正在编写一个涉及事件处理的API,我希望能够为处理程序使用块。回调通常需要访问或修改self。在ARC模式下,Clang警告说,引用self的块可能会创建一个retain循环,这似乎是一个有用的警告,我希望在一般情况下继续

但是,对于API的这一部分,回调的生命周期和包含的对象是在外部维护的。我知道当对象应该被释放时,我可以打破这个循环

我可以使用
#pragma clang diagnostic ignored“-Warc retain cycles”
关闭每个文件的保留周期警告,但这会禁用整个文件的警告。我可以用
#pragma-clangdiagnostic-push
pop
围绕该警告来包围这些块,但这会让这些块变得难看

我还可以通过引用指向self的_弱变量而不是直接引用self来得到警告,但这会使块使用起来不那么愉快

我想到的最好的解决方案是这个宏,它对块进行诊断禁用:

#define OBSERVE(OBJ, OBSERVEE, PATH, CODE) \
[(OBJ) observeObject:(OBSERVEE) forKeyPath:(PATH) withBlock:^(id obj, NSDictionary *change) { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-retain-cycles\"") \
do { CODE; } while(0); \
_Pragma("clang diagnostic pop") \
}];
__weak typeof(self) weakSelf = self; // iOS ≥ 5
__unsafe_unretained typeof(self) unsafeUnretainedSelf = self; // 5 > iOS ≥ 4
__block typeof(self) blockSelf = self; // ARC disabled

这是可行的,但它对API用户来说不是很容易发现,它不允许嵌套的观察者,而且它与XCode编辑器的交互也很差。有没有更好的方法来禁用或避免警告?

首先,有一种简单的方法可以使用
#pragma
禁用某些代码行的警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "<#A warning to ignore#>"
<#Code that issues a warning#>
#pragma clang diagnostic pop

新的LLVM能够更好地检测/防止此类保留周期 等待ios6提供LLVM,或者按照alex的方式创建弱var


但是禁用警告是个坏主意

我认为禁用警告是目前唯一正确的方法,因为它说编译器:不关心这个保留周期,我知道它,我会自己处理观察者。
引入弱引用是一个代价高昂的解决方案,因为它会带来运行时CPU和内存开销。

我编写了以下宏,我认为这非常聪明

#define CLANG_IGNORE_HELPER0(x) #x
#define CLANG_IGNORE_HELPER1(x) CLANG_IGNORE_HELPER0(clang diagnostic ignored x)
#define CLANG_IGNORE_HELPER2(y) CLANG_IGNORE_HELPER1(#y)

#define CLANG_POP _Pragma("clang diagnostic pop")
#define CLANG_IGNORE(x)\
    _Pragma("clang diagnostic push");\
    _Pragma(CLANG_IGNORE_HELPER2(x))
它允许你做各种有趣的事情(不用Xcode对你唠叨),比如

CLANG_IGNORE(-Warc-retain-cycles)
[object performBlock:^(id obj){ [obj referToSelfWithoutWarning:self]; }];
CLANG_POP
你可以在任何警告旗和叮当声将注意到你的突发奇想

CLANG_IGNORE(-Warc-performSelector-leaks);
return [self performSelector:someIllBegotSelector withObject:arcFauxPas];
CLANG_POP

同样,警告通常是有原因的。聚会爆笑者。

为了解决创建弱引用的笨拙问题,我将其放入了一个宏中。它使用预处理器创建具有相同名称但带有前缀的新var(在本例中为“w”);我避免使用“弱”,因为这样做会过多,并且会使资本化规则更加混乱):


如果,哦,弱引用是不可取的,不要使用它!我喜欢将对象作为参数传递的nielsbot解决方案(当然,在可能的情况下)。

创建一个
\u弱
引用
self
实际上需要一行代码。我认为在这种情况下解决问题比试图缓解症状要好。引用
weakSelf
而不是
self
如何使块使用起来不那么愉快?有两种方式不太令人愉快。听众通常很简短,有时是一句话。弱声明将侦听器的大小增加一倍。这还意味着您需要限定属性访问,而不是使用推断的self。我同意,我目前的解决方案可能比仅仅使用uu-weak更糟糕,但我希望通过这个问题得到一个更好的解决方案。你能改变你的完成块的原型来接受“自我”论证吗?现在,传递块的代码看起来是一样的(除了接受一个额外的参数),您可以消除警告。(即,让您的API将相关对象传递给您的块)此外,这里的一些代码示例可能很好
self
没有在足够多的块中使用,因此为其添加签名会引入更多噪声。我已经接受了马克的立场,那就是声明一个
\uu弱
引用
自我
并没有为了摆脱它而争吵那么邪恶。如果他想添加他的评论作为回答,我会将其标记为已接受。
#define WEAK_VAR(NAME) __unsafe_unretained typeof(NAME) w##NAME = NAME

...
WEAK_VAR(self);
self.block = ^{
    [wself doStuff];
};