我正在编写一个涉及事件处理的API,我希望能够为处理程序使用块。回调通常需要访问或修改self。在ARC模式下,Clang警告说引用self的块可能会创建一个保留周期,这似乎是一个有用的警告,我想继续保持。
但是,对于我的这部分API,回调的生命周期和包含对象在外部进行维护。我知道当对象应该被释放时我可以打破循环。
我可以使用#pragma clang diagnostic ignored "-Warc-retain-cycles"
在每个文件的基础上关闭保留周期警告,但是会禁用整个文件的警告。我可以用#pragma clang diagnostic push
和pop
围绕那个警告来围绕这些街区,但这会让这些街区难看。
我还可以通过引用指向self的__weak变量而不是直接引用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") \
}];
这是有效的,但它对于API用户来说不是很容易被发现,它不允许嵌套的观察者,并且它与XCode的编辑器交互不良。有没有更好的方法来禁用或避免警告?
答案 0 :(得分:7)
首先,有一种简单的方法可以使用#pragma
禁用某些代码行的警告:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "<#A warning to ignore#>"
<#Code that issues a warning#>
#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
答案 1 :(得分:1)
我认为禁用警告是目前唯一正确的方法,因为它说编译器:不关心这个保留周期,我知道它,我会自己处理观察者。 引入弱引用是一种代价高昂的解决方案,因为它带有运行时CPU和内存开销。
答案 2 :(得分:1)
我写了下面的宏,其中我认为,非常聪明......
#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 haranguing you ),例如..
CLANG_IGNORE(-Warc-retain-cycles)
[object performBlock:^(id obj){ [obj referToSelfWithoutWarning:self]; }];
CLANG_POP
你可以加上任何警告标志,而Clang会留意你的想法......
CLANG_IGNORE(-Warc-performSelector-leaks);
return [self performSelector:someIllBegotSelector withObject:arcFauxPas];
CLANG_POP
然后,警告通常是有原因的。党派人物。
答案 3 :(得分:0)
新的LLVM更好地检测/防止此类保留周期 等待LLVM与ios6一起发货,或者用alex创建一个弱变量。
禁用警告是个坏主意!
答案 4 :(得分:0)
为了解决创建弱引用的笨拙问题,我将其放入宏中。它使用预处理器来创建一个具有相同名称但带有前缀的新var(在这种情况下为“w”;我避免使用'弱',因为这样做会过度杀戮并且更多地使用大小写规则):
#define WEAK_VAR(NAME) __unsafe_unretained typeof(NAME) w##NAME = NAME
...
WEAK_VAR(self);
self.block = ^{
[wself doStuff];
};
如果,otoh,弱引用是不可取的,请不要使用它!我喜欢nielsbot将对象作为参数传递的解决方案(当然可能的话)。