Отправка нераспознанного селектора на объект, зачем закрывать приложение? - PullRequest
1 голос
/ 05 июня 2011

При изучении target-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 ]

2 голосов
/ 05 июня 2011

Сбой из-за того, что по умолчанию для объекта, который получает нераспознанный селектор, выбрасывается исключение.

А если у вас нет блока @try / @catch, который перехватывает исключение, необработанныйисключение приводит к прекращению работы приложения.

Однако вы можете изменить это поведение по умолчанию, переопределив методы, обрабатывающие нераспознанный селектор. Проверьте эти методы NSObject :

  • forwardingTargetForSelector:
  • resolInstanceMethodDynamically:
  • forwardInvocation:
  • didNotRecognizeSelector:

Здесь также есть хорошая статья Майка Эша здесь , которая дает хорошую общую сводку.

Разница, которую покупает динамизм, заключается в том, что вы генерируете исключение для нераспознанного селектора, который позволяет вам решить, как реагировать на ошибку (вместо немедленного выхода из-за ошибки сегментации).Вы также можете переопределить, как объекты реагируют на нераспознанные селекторы.Однако вы хотите, чтобы они генерировали исключения в большинстве случаев, потому что обычно это признак того, что вы сделали что-то не так.

1 голос
/ 05 июня 2011

Как уже упоминалось, вы пытаетесь отправить сообщение объекту, на который невозможно ответить.Для делегатов имеет смысл посмотреть, отвечают ли они селектору, прежде чем отправлять им сообщения.Эта проверка должна выглядеть примерно так:

if ( [delegate respondsToSelector:@selector(DoneLoadingNoStoriesFound:)] ) {
    [delegate DoneLoadingNoStoriesFound:YES];
}
0 голосов
/ 23 декабря 2015

Я думаю, что вы ошиблись в том, что вы действительно можете отправлять любые сообщения объекту, даже если он не отвечает на него во время компиляции , а не во время выполнения.Этот шаблон возможен, потому что классы могут быть изменены во время выполнения, чтобы они могли отвечать на дополнительные сообщения.Однако, если вы пойдете этим путем, вам нужно будет принять меры и обработать случаи, когда объект не отвечает на конкретное сообщение, либо с помощью try-catch, либо чем-то еще.

0 голосов
/ 23 декабря 2015

Создайте хорошую привычку, например if ( [delegate respondsToSelector:@selector(DoneLoadingNoStoriesFound:)] ) { [delegate DoneLoadingNoStoriesFound:YES]; }, если вы хотите отправить сообщение делегату.

0 голосов
/ 05 июня 2011

Если я что-то упустил, исключение выдается, как вы заметили, но нет ничего, что могло бы его перехватить, поэтому приложение завершается.

...