【发布时间】:2012-01-05 06:34:53
【问题描述】:
我正在编写一个涉及事件处理的 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 的编辑器的交互很差。有没有更好的方法来禁用或避免警告?
【问题讨论】:
-
创建对
self的__weak引用实际上只需要一行代码。我认为在这种情况下解决问题比试图缓解症状要好。引用weakSelf而不是self如何使块的使用变得不那么愉快? -
这在几个方面不太令人愉快。听众通常很短,有时是一个单一的陈述。 __weak 声明使侦听器的大小加倍。这也意味着您需要限定属性访问而不是使用推断的自我。我同意我目前的解决方案可能比仅使用 __weak 更糟糕,但我希望通过这个问题得到一个更好的解决方案。
-
你能改变你的完成块的原型来接受一个“自我”参数吗?现在你传递你的块的代码看起来是一样的(除了接受一个额外的参数),你可以消除警告。 (即让您的 API 将相关对象传递给您的块)
-
另外,一些代码示例在这里可能很好
-
self没有在足够多的块中使用,因此为其添加签名会引入更多噪音。我已经开始接受 Mark 的立场,即声明__weak引用self比所有这些为摆脱它而争吵要邪恶。如果他想添加他的评论作为答案,我会将其标记为已接受。
标签: objective-c objective-c-blocks clang automatic-ref-counting