方案
if (delegate && [delegate respondsToSelector:@selector(aboutTextUpdated:)]) {
[delegate aboutTextUpdated:aboutText];
}
为了简化我项目中的这种检查,我创建了几个c函数,如下所示。
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id callSelectorOnDelegateWithObject(SEL selector,NSObject *delegate,id object)
{
if (delegate != nil && [delegate respondsToSelector:selector] == YES)
{
if (object != nil)
{
return [delegate performSelector:selector withObject:object];
}
else
{
return [delegate performSelector:selector];
}
}
return nil;
}
id callSelectorOnDelegate(SEL selector,NSObject *delegate)
{
if (delegate != nil && [delegate respondsToSelector:selector] == YES)
{
return [delegate performSelector:selector];
}
return nil;
}
#pragma clang diagnostic pop
他们被称为如下
callSelectorOnDelegateWithObject(@selector(aboutTextUpdated:), delegate, aboutText);
问题
我有时会出现EXC_BAD_ACCESS错误,但不能以可重现的方式出现。调用c函数但在执行第一个语句之前发生异常。当我用实际的if语句替换函数调用时,错误永远不会发生。为了满足项目的最后期限,我继续进行了这一改变。但是,我无法摆脱这种错误。
导致错误的原因是什么?
更多背景
答案 0 :(得分:1)
我们需要了解崩溃的详细信息才能了解更多信息。我最好的猜测是偶尔会调用callSelectorOnDelegateWithObject()
,其中object
为nil
,但selector
标识的方法实际上确实需要参数。在这种情况下,您只使用-performSelector:
,而不是-performSelector:withObject:
。因此,该方法接收其参数的垃圾。
如果某些代码调用callSelectorOnDelegateWithObject()
而不是callSelectorOnDelegate()
,那么您应该无条件地传递object
参数。传递nil
的呼叫者并不意味着您可以放弃参数。 nil
可能(或者至少可能)很重要。
那就是说,这整个方法似乎不是一个好主意。我不会发现这个方案比问题顶部的代码片段更简单。
您可以通过不明确检查delegate
是否为非nil
来简化该代码段。如果-respondsToSelector:
为delegate
,则nil
检查将返回false,因为消息nil
始终会导致错误。
最后,您绝不应与YES
(或TRUE
等)进行比较。您正在使用一个已经是布尔表达式的表达式,然后将其作为复合布尔表达式。让我问你是否会编写如下代码:
if (([delegate respondsToSelector:selector] == YES) == YES)
...
如果你不写第二个== YES
(以及与YES
进行进一步比较的无限序列),那么你应该理解为什么你不应该写第一个。{/ p>
除此之外,任何非零值都是真值。 YES
只是一个这样的价值。对于返回布尔值的任何给定方法,您无法确定它返回的真值实际上是YES
而不是任何其他真值。