问题 有没有办法在Objective-C中捕获发送到nil的消息?


我刚被一个讨厌的人咬伤了 窃听器 在Objective-C中,“发送消息到nil是好的”行为使得这一点变得模糊不清。

我见过 发送消息给nil?,共识似乎是“我们如何滚动”Objective-C。

现在,也许我没有足够的Objective-C经验,但似乎陷入困境似乎是有用的,因为我无法想到为什么会发生这种情况的一个很好的理由  的时间。然而,它可能只是一个我不习惯的编码习语。

除了像以下那样检查nil之外:

assert( object != nil );
[object message];

有没有办法让运行时捕获这种情况,并在何时发出警告 object 没有?


6885
2018-05-27 05:56


起源

为什么不尝试用Objective-C语言编写,而不是将Java惯用语移植到Objective-C? - runako
我不知道,我不用Java编写代码。显然,其他人发现这很有用(见下面的答案)。 - Justicle
s / Java /另一种编程语言/。学习任何环境中的本土习语通常会使您在该环境中更有效率。不要打你的工具。 - runako
我只是问问。这就是stackoverflow的用途。 - Justicle


答案:


你可以用一个 ObjC没有文档的技巧或dtrace (请参阅dtrace解决方案的注释)。

pid$1::objc_msgSend:entry
/arg0==0/
{
  ustack();
}

9
2018-05-27 06:11



真棒。当我的眼睛止血时,我会试一试:-) - Justicle


nil消息传递在ObjC中非常常用。人们可以争论这是好还是坏;这只是你必须习惯的东西。如果你试图用技巧来打破它,那么你将打破Cocoa,因为Cocoa使用它。有一些技巧(如发布的diciu)可以在你怀疑没有消息的情况下进行调试,但似乎无法找到它。但是你不能把这些留在你的代码中(上面的博客文章清楚地说明了这一点)。零消息传递在框架内部太常见了。

但是,对于你原来的点,比较:

- (void)doSomethingWith:(id)x {
    NSAssert(x != nil, @"Don't pass me nil");
    [x something];
}

void Bar::DoSomething(Foo *x) {
    assert(x != NULL);
    if (x != NULL) {
       x.something;
    }
}

在这两种情况下,您都需要进行测试,在这两种情况下,如果您未能测试,编译器将不会发出警告。唯一的区别是你崩溃/断言的情况。就个人而言,我写的是宏 NSAssert() 做到了 总是 如果失败则打印日志消息。它只是在Debug中崩溃。这样,当客户向我发送日志时,我可以看到哪些断言失败了。


4
2018-05-27 13:02



谢谢Rob,我只是为了简洁而包含了硬断言 - 我不是发布 - 构建断言崩溃的粉丝。我认为整个发送消息到零的东西是我将习惯的东西。尽管如此,它值得深入了解并了解更多关于幕后发生的事情 - 每个人都赢了! - Justicle