将无法识别的选择器发送到对象,为什么要终止应用程序?

时间:2011-06-05 16:01:19

标签: objective-c objective-c-runtime

在研究Objective-C时,它的高度动态性的一个后果是,即使在运行时它不会响应它,也可以向对象发送任何消息。

然后它将忽略该消息并引发异常。

在实际情况中,我正在尝试向委托对象发送一条消息,该委托对象在委托中没有实现。

当然,我必须实现它以获得我的功能,但纯粹是出于我的兴趣,我想知道为什么我的应用程序在我不应用时崩溃。

2011-06-05 17:44:39.280 myTest[28158:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TVC DoneLoadingNoStoriesFound:]: unrecognized selector sent to instance 0x5c0ef90'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x015cabe9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x0171f5c2 objc_exception_throw + 47
    2   CoreFoundation                      0x015cc6fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x0153c366 ___forwarding___ + 966
    4   CoreFoundation                      0x0153bf22 _CF_forwarding_prep_0 + 50
    5   myTest                             0x0003db93 -[Loader loadTasksForStoriesForDisplayedWorkpace] + 1268
    6   myTest                             0x0003d388 -[Loader requestFinished:] + 1936
    7   myTest                             0x00017f2e -[ASIHTTPRequest reportFinished] + 100
    8   Foundation                          0x001f69a6 __NSThreadPerformPerform + 251
    9   CoreFoundation                      0x015ac01f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    10  CoreFoundation                      0x0150a28b __CFRunLoopDoSources0 + 571
    11  CoreFoundation                      0x01509786 __CFRunLoopRun + 470
    12  CoreFoundation                      0x01509240 CFRunLoopRunSpecific + 208
    13  CoreFoundation                      0x01509161 CFRunLoopRunInMode + 97
    14  GraphicsServices                    0x01b0f268 GSEventRunModal + 217
    15  GraphicsServices                    0x01b0f32d GSEventRun + 115
    16  UIKit                               0x0048642e UIApplicationMain + 1160
    17  myTest                             0x0000272b main + 85
    18  myTest                             0x000026cd start + 53
)
terminate called after throwing an instance of 'NSException'
Program received signal:  “SIGABRT”.
kill
quit

5 个答案:

答案 0 :(得分:2)

它崩溃了,因为接收无法识别的选择器的对象的默认行为是抛出异常。

如果您没有捕获异常的@try / @catch块,则未捕获的异常会导致您的应用程序终止。

但是,您可以通过覆盖处理无法识别的选择器的方法来更改此默认行为。 Check out these NSObject methods

  • forwardingTargetForSelector:
  • resolveInstanceMethodDynamically:
  • forwardInvocation:
  • doesNotRecognizeSelector:

Mike Ash here也有一篇很好的文章,它提供了一个很好的整体总结。

动态购买的不同之处在于您在无法识别的选择器上抛出异常,这使您可以决定如何响应错误(而不是立即退出分段错误)。您还可以选择覆盖对象如何响应无法识别的选择器。但是,你确实希望他们在大多数情况下抛出异常,因为这通常表明你做错了。

答案 1 :(得分:1)

就像已经提到的那样,您正在尝试向无法响应的对象发送消息。对于代理人来说,在发送消息之前看看他们是否响应选择器是有意义的。那个检查应该是这样的,

if ( [delegate respondsToSelector:@selector(DoneLoadingNoStoriesFound:)] ) {
    [delegate DoneLoadingNoStoriesFound:YES];
}

答案 2 :(得分:0)

除非我遗漏了某些内容,否则会抛出异常,但是没有任何内容可以捕获它,因此应用程序终止。

答案 3 :(得分:0)

当你想向委托发送消息时,养成像if ( [delegate respondsToSelector:@selector(DoneLoadingNoStoriesFound:)] ) { [delegate DoneLoadingNoStoriesFound:YES]; }这样的好习惯。

答案 4 :(得分:0)

我认为你错了的是你确实可以将任何你想要的消息发送给一个对象,即使它没有在编译时响应它,而不是运行时。这种模式是可行的,因为可以在运行时修改类,以便它们可以响应其他消息。当你走这条路的时候,你需要采取措施并在对象没有响应特定消息时处理案例,无论是使用try-catch还是其他东西。

相关问题