Ну, я думаю, что это может быть описано с помощью очень изобретенного примера. Скажем, у Вас есть метод в Java, который распечатывает все элементы в ArrayList:
void foo(ArrayList list)
{
for(int i = 0; i < list.size(); ++i){
System.out.println(list.get(i).toString());
}
}
Теперь, если Вы называете тот метод как так: someObject.foo (ПУСТОЙ УКАЗАТЕЛЬ); Вы собираетесь, вероятно, получить NullPointerException, когда он пробует к списку доступа, в этом случае в вызове к list.size (); Теперь, Вы, вероятно, никогда не называли бы someObject.foo (ПУСТОЙ УКАЗАТЕЛЬ) с Нулевым значением как этот. Однако Вы, возможно, получили свой ArrayList из метода, который возвращает ПУСТОЙ УКАЗАТЕЛЬ, если он сталкивается с некоторой ошибкой при генерации ArrayList как someObject.foo (otherObject.getArrayList ());
, Конечно, у Вас также будут проблемы, если Вы сделаете что-то вроде этого:
ArrayList list = NULL;
list.size();
Теперь, в Objective C, у нас есть эквивалентный метод:
- (void)foo:(NSArray*)anArray
{
int i;
for(i = 0; i < [anArray count]; ++i){
NSLog(@"%@", [[anArray objectAtIndex:i] stringValue];
}
}
Теперь, если у нас есть следующий код:
[someObject foo:nil];
у нас есть та же ситуация, в которой Java произведет NullPointerException. К нулевому объекту получат доступ сначала в [anArray количество] Однако вместо того, чтобы бросить NullPointerException, Objective C просто возвратится 0 в соответствии с правилами выше, таким образом, цикл не будет работать. Однако, если мы устанавливаем цикл для выполнения количества раз набора, затем мы сначала отправляем сообщение в anArray в [anArray objectAtIndex:i]; Это также возвратится 0, но с тех пор objectAtIndex: возвращает указатель, и указателем на 0 является НОЛЬ/ПУСТОЙ УКАЗАТЕЛЬ, NSLog будет переданным нолем каждый раз через цикл. (Хотя NSLog является функцией и не методом, он распечатывает (пустой указатель), если передано ноль NSString.
В некоторых случаях более хорошо иметь NullPointerException, так как можно сказать сразу же, что что-то неправильно с программой, но если Вы не поймаете исключение, программа откажет. (В C, пытаясь разыменовать ПУСТОЙ УКАЗАТЕЛЬ таким образом заставляет программу отказывать.) В Objective C, это вместо этого правые дела возможно неправильное поведение во время выполнения. Однако, если у Вас есть метод, который не повреждается, если он возвращается, 0/nil/NULL/a обнулил структуру, затем это сохраняет Вас от необходимости проверить для проверки, объект или параметры являются нолем.
То, что это означает, - то, что время выполнения не производит ошибку, когда objc_msgSend называют на нулевом указателе; вместо этого это возвращает некоторых (часто полезный) значение. Сообщения, которые могли бы иметь побочный эффект, ничего не делают.
Это полезно, потому что большинство значений по умолчанию является более соответствующим, чем ошибка. Например:
[someNullNSArrayReference count] => 0
Т.е. ноль, кажется, пустой массив. При сокрытии ноля ссылка NSView ничего не делает. Удобный, а?
Это означает часто не иметь необходимость проверить на нулевые объекты везде для безопасности - особенно:
[someVariable release];
или, как отмечено, различные методы количества и длины весь возврат 0, когда у Вас есть нулевое значение, таким образом, Вы не должны добавлять дополнительные проверки на ноль на всем протяжении:
if ( [myString length] > 0 )
или это:
return [myArray count]; // say for number of rows in a table
Не думайте о "получателе, являющемся нолем"; я соглашаюсь, это довольно странно. При отправке сообщения в ноль нет никакого получателя. Вы ни во что просто отправляете сообщение.
то, Как иметь дело с этим, является философским различием между Java и Objective C: в Java это - ошибка; в Objective C это нет.
В цитате из документации существует два отдельных понятия - возможно, могло бы быть лучше, если бы документация сделала это более ясным:
существует несколько шаблонов в Какао, которые используют в своих интересах этот факт.
значение, возвращенное от сообщения до ноля, может также быть допустимым:
Первый, вероятно, более релевантен здесь: обычно способность отправить сообщения в nil
делает код более простым - Вы не должны проверять на нулевые значения везде. Каноническим примером является, вероятно, метод доступа:
- (void)setValue:(MyClass *)newValue {
if (value != newValue) {
[value release];
value = [newValue retain];
}
}
При отправке сообщений в nil
не были допустимы, этот метод будет более сложным - у Вас должно было бы быть две дополнительных проверки для обеспечения value
, и newValue
не nil
прежде, чем отправить им сообщения.
последний вопрос (который оценивает, возвратился от сообщения до nil
, является также обычно актуальным), тем не менее, добавляет эффект множителя к первому. Например:
if ([myArray count] > 0) {
// do something...
}
Этот код снова не требует проверки на nil
значения и течет естественно...
Все это сказало, дополнительная гибкость, что способность отправить сообщения в nil
действительно прибывает в некоторую стоимость. Существует возможность, что Вы будете на некотором этапе писать код, который перестал работать специфическим способом, потому что Вы не приняли во внимание возможность, что значение могло бы быть nil
.
Сообщение к nil
не делает ничего и возвратов nil
, Nil
, NULL
, 0
, или 0.0
.
Все другие сообщения корректны, но возможно это - понятие, это - вещь, важная здесь.
В вызовах метода Objective C, любая ссылка на объект, которая может принять селектор, является допустимой целью для того селектора.
Это сохраняет МНОГО из, "целевой объект типа X?" код - пока принимающий объект реализует селектор, он делает абсолютно никакое различие , каково класс это! nil
NSObject, который принимает любой селектор - он просто не делает , делают что-либо. Это устраняет большую "проверку на ноль, не отправляйте сообщение если истинный" код также. ("Если это принимает его, это реализует его" понятие, также, что позволяет Вам создавать протоколы , которые являются видом отчасти как интерфейсы Java: объявление, что, если класс реализует установленные методы, то он соответствует протоколу.)
причина этого состоит в том, чтобы устранить код обезьяны, который не делает ничего кроме, угождают компилятору. Да, Вы получаете издержки еще одного вызова метода, но Вы сохраняете время программиста , который является намного более дорогим ресурсом, чем процессорное время. Кроме того, Вы устраняете больше кода и больше условной сложности из Вашего приложения.
Разъяснение для downvoters: можно думать, что это не хороший способ пойти, но это - как язык реализован, и это - рекомендуемая идиома программирования в Objective C (см. лекции программирования iPhone Стэнфорда).
Сообщения ObjC, которые отправляются в ноль и чьи возвращаемые значения имеют размер, больше, чем sizeof (пусто*) производят неопределенные значения на процессорах PowerPC. В дополнение к этому эти сообщения заставляют неопределенные значения быть возвращенными в областях структур, размер которых больше, чем 8 байтов на процессорах Intel также. Vincent Gable описал это приятно в его сообщение в блоге