1

在研究 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
4

5 回答 5

2

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

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

但是,您可以通过覆盖处理无法识别的选择器的方法来更改此默认行为。查看这些 NSObject 方法

  • 转发目标选择器:
  • 动态解析实例方法:
  • 前向调用:
  • 不识别选择器:

Mike Ash在这里也有一篇不错的文章,它给出了一个很好的总体总结。

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

于 2011-06-05T16:12:48.933 回答
1

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

if ( [delegate respondsToSelector:@selector(DoneLoadingNoStoriesFound:)] ) {
    [delegate DoneLoadingNoStoriesFound:YES];
}
于 2011-06-05T16:35:04.633 回答
0

除非我遗漏了某些东西,否则会如您所述抛出异常,但没有任何东西可以捕获它,因此应用程序终止。

于 2011-06-05T16:12:18.570 回答
0

养成一个好习惯,比如if ( [delegate respondsToSelector:@selector(DoneLoadingNoStoriesFound:)] ) { [delegate DoneLoadingNoStoriesFound:YES]; }每当您想向代表发送消息时。

于 2015-12-23T09:57:34.463 回答
0

我认为你错了,你确实可以向对象发送任何你想要的消息,即使它在编译时没有响应,而不是运行时。这种模式是可能的,因为可以在运行时修改类,以便它们可以响应其他消息。当您这样做时,您将需要采取措施并处理对象未响应特定消息的情况,无论是使用 try-catch 还是其他方式。

于 2015-12-23T10:33:14.710 回答