有没有人知道为什么NextStep / Apple决定采用“方便的方法”,当传递一个Nil对象一个消息时,什么都不做,但是在传递一个被实例化的对象一个无效选择器时引发异常的“
Java方法”
例如,
// This does "nothing" NSObject *object = Nil; [object thisDoesNothing]; object = [[NSObject alloc] init]; // This causes an NSInvalidArgumentException to be raised [object thisThrowsAnException];
所以一方面,我们有方便的没有检查Nil(假设我们不太在意方法调用的结果) – 但另一方面,如果我们的对象我们必须检查异常没有回应方法?
如果我不确定对象是否会响应,我必须:
@try { [object thisThrowsAnException]; } @catch (NSException *e){ // do something different with object,since we can't call thisThrowsAnException }
要么,
if([object respondsToSelector:@selector(thisThrowsAnException)]) { [object thisThrowsAnException]; } else { // do something different with object,since we can't call thisThrowsAnException }
(后者可能是更好的方法,因为如果对象是Nil,则选择器不会引发异常,因此您的代码可能不会按照您的要求执行).
我的问题是:
为什么苹果决定以这种方式实施?
为什么没有对实例化对象无法识别的选择器调用不会引发异常?
或者,为什么没有Nil对象引发异常,如果您尝试调用它的方法?
解决方法
我不能完全回答你的问题,但我可以回答你的一些问题. Objective-C允许您将消息发送到nil,因为它使代码更加优雅.
You can read about this design decision here,我将窃取榜样:
假设您想要获取某人在办公室电话上拨打的最后一个电话号码.如果你不能发送消息到nil,你必须这样写:
Office *office = [somePerson office]; // Person might not have an office,so check it... if (office) { Telephone *phone = [office telephone]; // The office might not have a telephone,so check it... if (phone) { NSString *lastNumberDialed = [phone lastNumberDialed]; // The phone might be brand new,so there might be no last-dialed-number... if (lastNumberDialed) { // Use the number,for example... [myTextField setText:lastNumberDialed]; } } }
现在假设你可以发送消息到nil(并总是没有回来):
NSString *lastNumberDialed = [[[somePerson office] telephone] lastNumberDialed]; if (lastNumberDialed) { [myTextField setText:lastNumberDialed]; }
至于为什么发送一个无法识别的选择器到一个对象引发了一个例外:我不知道肯定.我怀疑这是一个更为常见的bug,而不是无害的.在我的代码中,当我需要发送一个可选的协议消息(例如向代理发送一个可选消息)时,我只希望一个无法识别的选择器被忽略.所以我希望系统将其视为一个错误,让我在相对罕见的情况下显而易见,当我不希望它是一个错误.
请注意,您可以通过几种不同的方式处理您自己的课程中无法识别的选择器(在某种程度上).看看forwardingTargetForSelector :,forwardInvocation :,doesNotRecognizeSelector :,和resolveInstanceMethod:NSObject
的方法.