嗯,这确实是一个难题。
我并没有看到直接的解决方案。让我们仔细思考一下:
现在,您可能有一个大型代码库,在其中使用此日志记录宏。这很好,但由于在块中引用了self
而创建了保留周期,因此它会创建一些内存泄漏。(或者,如果它没有创建内存泄漏,那么它正在威胁着。)
所以,您只需要确保对self
的引用(概念上)是弱引用即可。听起来很合理。
让我们看看您的要求:
第一个要求
可以是多行宏,其中定义了对self的__weak引用。您建议这个棘手的部分可能是它可能重新定义弱引用(可能通过在同一段代码中多次使用)。这可以相对容易地通过将宏包装在do { something(); } while(0)
结构中来解决。
#define JELogVerbose(fmt, ...)
do
{
__weak __typeof(self) weakSelf = self;
DDLogVerbose((@"%@ %@ - " fmt), NSStringFromClass([weakSelf class]),
NSStringFromSelector(_cmd), ##__VA_ARGS__)
} while (0)
这是一种非常常见的宏模式。如果您连续两次调用该宏,weakSelf变量仍不会被重新定义。但是,您可能会注意到,这实际上对解决问题没有任何帮助,因为您必须引用self才能获得其弱引用。实际上,您必须在创建块之前拥有weakSelf引用,然后在块中仅引用弱引用。事实上,通常情况下,您需要再创建一个强引用,以便它不会在您使用时被移除。像这样:
__weak typeof(self) weakSelf = self;
[someObj block:^{
__strong __typeof(weakSelf) strongSelf = weakSelf;
MyLog(strongSelf);
}];
为了解决这个问题,你必须已经拥有一个对自身的弱引用,或者有一个跨越块创建的宏。(那将是相当棘手的。)
第二个要求
我们不能使用这些有用的预处理器标准宏,因为它们不会告诉你在运行时发生了什么,而是在编译时(更准确地说是预处理时间)。你还正确地拒绝了另一个答案,因为它提供了来自编译时的信息(更接近了,但仍然不够)而不是运行时。
不幸的是,我认为你无法在没有实际引用它的情况下获得你正在寻找的
self
的运行时信息。我们只是不知道在编译时对象的类实际上会是什么。所以所有那些
PRETTY_FUNCTION的技巧都被排除了。当然,正如人们所期望的那样,所有的运行时函数都需要一个对你想要查找类的对象的引用。
第三个要求
我要把这个问题简化为:我不想改变我的代码库。可以理解。
虽然,我认为你别无选择。你有点陷入了困境。
结论
我认为你没有太多好的选择(它们都需要在宏之外做出更改,也就是说要修改你的代码库):
- 通过删除对self的任何引用并始终在block中使用它,创建一个块安全版本的宏
- 创建一个块安全版本的宏,它使用strongSelf,然后每当你使用它时,你还必须在block之外创建weakSelf引用,并在block内部创建一个strongSelf(就像上面的例子一样)。这比较麻烦,但可以保留现有的所有日志记录。
祝你好运!
({...})
中,以避免在同一作用域内多次使用时重新声明SelfType
,并确保整体的健康性 :) - Sash Zats