2009-05-27 1 views
11

Я только что был укушен раздражающим bug, который был неясным поведением «отправить сообщение нильски нормально» в Objective-C.Есть ли способ улавливать сообщения, отправленные на ноль в Objective-C?

Я видел Sending a message to nil?, и консенсус, похоже, «то, как мы катимся» в Objective-C.

Теперь, возможно, у меня недостаточно опыта в Objective-C, но, похоже, было бы полезно поймать это, потому что я не могу придумать, почему это должно происходить most of время. Тем не менее, это может быть просто идиллический код, к которому я еще не привык.

Так, кроме проверки на ноль везде так:

assert(object != nil); 
[object message]; 

Есть ли способ, чтобы сделать во время выполнения ловушки это условие, и предупредить, когда object равна нулю?

+2

Почему бы не попытаться написать в Objective-C идиоме вместо переноса идиом Java в Objective-C? – runako

+1

Я бы не знал, я не кодирую на Java. Очевидно, что другие люди считают это полезным (см. Ответ ниже). – Justicle

+1

s/Java/другой язык программирования /. Изучение родных идиом любой среды, как правило, сделает вас более продуктивными в этой среде. Не боритесь с инструментами. – runako

ответ

9

Вы можете использовать ObjC undocumented trick or dtrace (см. Комментарии для решения dtrace).

pid$1::objc_msgSend:entry 
/arg0==0/ 
{ 
    ustack(); 
} 
+5

Awesome. Когда мои глаза прекратят кровотечение, я попробую :-) – Justicle

4

nil обмен сообщениями используется в ObjC очень часто. Люди могут бороться, хорошо это или плохо; это просто то, к чему вы должны привыкнуть. Если вы попытаетесь сломать его с помощью трюков, то вы собираетесь сломать какао, потому что Какао использует его. Есть некоторые трюки (например, опубликованные diciu), которые позволят отлаживать в ситуациях, когда вы подозреваете, что обмен сообщениями отсутствует, но просто не может найти его. Но вы не можете просто оставить их в своем коде (и сообщение в блоге выше делает это понятным). nil обмен сообщениями слишком распространен внутри фреймворков.

К исходной точке, хотя, сравните:

- (void)doSomethingWith:(id)x { 
    NSAssert(x != nil, @"Don't pass me nil"); 
    [x something]; 
} 

против

void Bar::DoSomething(Foo *x) { 
    assert(x != NULL); 
    if (x != NULL) { 
     x.something; 
    } 
} 

В обоих случаях вам необходимо проверить, и в обоих случаях компилятор не предупредит вас, если вы не можете проверить. Единственное различие заключается в том, в каких случаях вы терпите крах/утверждаете. Лично я пишу макросы около NSAssert(), которые делают его всегда распечатывают сообщение журнала, если оно не удается. Он просто падает только в Debug. Таким образом, когда клиент отправляет мне журналы, я могу видеть, какие утверждения не удалось.

+0

Спасибо, Роб, я просто включил твердый аргумент для краткости - я не поклонник сбоев, связанных с выпуском релиза. Я думаю, что все сообщение send-message-to-nil - это то, к чему я просто привыкну. Тем не менее, его стоит спросить и узнать немного больше о том, что происходит под капотом - все побеждают! – Justicle