Ссылке на экземпляр очень легко оказаться указывающей на не экземпляр — то есть на nil.

Я уже говорил, что простое объявление экземпляра без инициализации устанавливает ссылку равной nil (при наличии механизма ARC) и что многие методы каркаса Cocoa преднамеренно возвращают nil как способ указать, что что-то пошло не так. Кроме того, экземпляр переменной, объявленной как ссылка на объект, начинает жизнь как nil, и если эта ссылка не будет установлена впоследствии указывающей на реальный объект, как вы ожидаете, то она может так и остаться nil. (В главе 7”, мы рассмотрим все наиболее распространенные способы, которыми это может случиться.)

Рассмотрим последствия отправки сообщения неэкземпляру, т.е. по указателю nil. Вы можете отправить сообщение экземпляру NSString следующим образом:

NSString * s2 = [s uppercaseString];

Этот код посылает сообщение uppercaseString объекту s. Предположительно s представляет собой экземпляр NSString. Но что если s равен nil? В некоторых объектно-ори-ентированных языках программирования отправка сообщения ссылке nil вызывает ошибку времени выполнения и приводит к преждевременному завершению работы программы (например, в REALbasic и Ruby). Но Objective-C работает иначе. В Objective-C отправка сообщения nil допустима и не прерывает выполнение программы. Более того, если вы сохраните

результат вызова метода, он будет разновидностью нуля — что означает, что если вы присвоите этот результат ссылке на экземпляр, то он получит значение nil:

NSString* s = nil; //Сейчас s равно nil
NSString* s2 = [s uppercaseString]; // Теперь s2 тоже равно nil

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

Имеется не так много вариантов ваших действий — по сути, вы можете только наполнить ваш код сплошными проверками на равенство nil используемых ссылок на экземпляры. Описанное поведение в случае сообщения nil встроено в язык, и его никто не собирается менять. Поэтому вы просто обязаны знать его и постоянно о нем помнить! Считать, что у вас есть ссылка на реальный экземпляр, в то время как на самом деле у вас ссылка “в никуда” — это очень, очень распространенная ошибка начинающих, отягощенная тем, что при использовании ссылки nil никаких жалоб от среды выполнения не поступает, а ссылки nil в результате размножаются едва ли не в геометрической прогрессии. При этом ничего страшного не происходит, программа как-то работает, и некому разуверить вас в этом заблуждении (за исключением того, что программа ведет себя совершенно не так, как ожидалось). Если все тихо и таинственно идет не так, в первую очередь следует заподозрить наличие нулевой ссылки и использовать для расследования методы отладки (глава 9).

Словом, если вы заранее знаете, что вызов некоторого метода может вернуть nil, не думайте, что все пойдет хорошо и что он не вернет этот nil. Наоборот, если что-то может пойти не так — оно пойдет не так с большой вероятностью! Например, опустить проверку на равенство nil после вызова stringWithContentsOfFile:encoding:error: — это просто тупость. Меня не интересует, что вы точно знаете, что нужный файл имеется и что он именно в той кодировке, которую вы указали, — вы просто обязаны проверить результат на равенство nil!


 

 

 

Добавить комментарий