! vs == nil в objective-c
Если у вас есть такой объект, как NSString * someString, какая разница, если таковая имеется, между
if (!someString)
против
if (someString == nil)
Спасибо!
Ответы
Ответ 1
Первый синтаксис, который вы используете:
if (!someString)
использует своего рода "двусмысленность" C, вытекающую из того факта, что в исходном стандарте C не было надлежащего булева типа. Поэтому любое целое значение, равное 0, интерпретировалось как "ложное", а любое целое значение, отличное от "0", принималось как "истинное". Поэтому значение !
определяется на основе этого соглашения, а текущие версии стандарта C сохранили исходное определение для совместимости.
В вашем конкретном случае someString
является указателем, поэтому он сначала преобразуется в целое число, тогда ! someString
интерпретируется как значение bool true
, когда someString
указывает на местоположение 0x000000
, в противном случае он будет иметь значение "true".
Это нормально в большинстве условий (я бы сказал всегда), но теоретически NULL/nil
может отличаться от 0x000000
при определенных компиляторах, поэтому (в самой теории) было бы лучше использовать второй синтаксис, более явный:
if (someString == nil)
Это в любом случае более читаемо, и поскольку someString
не является целым числом (скорее, указателем), ИМО, лучшей практикой в целом.
EDIT: об определении NULL...
Является ли стандартом C значение NULL равным 0, является для меня интересной темой...
В соответствии с C99 standard, раздел 7.17, "Общие определения":
NULL [который] расширяется до константы нулевого указателя, определяемой реализацией;
Итак, NULL определяется в stddef.h с константой указателя нулевой указателя...
В том же документе на стр. 47 указано:
Целочисленное константное выражение со значением 0 или такое выражение, отличное от типа void *, называется константой нулевого указателя .55) Если константа нулевого указателя преобразуется в тип указателя, результирующий указатель, называемый нулевым указатель, не может сравниться с указателем на любой объект или функцию.
Таким образом, константа нулевого указателя (которая равна (void*)0
) может быть преобразована в нулевой указатель, и это гарантировано будет сравнивать неравномерность с указателем на любой объект или функцию.
Итак, я думаю, что в основном это зависит от того, решает ли реализация, что результат преобразования константы нулевого указателя в нулевой указатель создает указатель, который преобразуется обратно в целое число, дает 0. Неясно, интерпретирован ли нулевой указатель как целое число равно 0.
Я бы сказал, что стандарт действительно пытается установить нулевой указатель равным 0, но оставляет дверь открытой для систем, где нулевой указатель не был 0.
Ответ 2
Для большинства указателей они эквивалентны, хотя большинство кодировщиков, которых я знаю, предпочитают первое, поскольку оно более кратким.
Для слабосвязанных символов первый разрешает символ (и вызывает сбои, если он отсутствует), а явное сравнение с nil
или NULL
не будет.
Ответ 3
Синтаксис, восклицательный знак, !
оператор префикса в C не является логическим. По крайней мере, это его версия. Если вы посмотрите на типичную логическую таблицу не правды, вы увидите что-то вроде этого:
Input Result
1 0
0 1
Однако в C логический оператор не делает что-то более похожее:
Input Result
non-zero 0
0 1
Итак, если вы считаете, что как NULL, так и nil в Objective-C оцениваются в 0, вы знаете, что применяемый к ним логический оператор не приведет к 1.
Теперь рассмотрим оператор равенства ==
. Он сравнивает значение двух элементов и возвращает 1, если они равны, 0, если они не являются. Если вы сопоставили свои результаты с таблицей истинности, то она выглядела бы точно так же, как и результаты для логического не.
В программах C и Objective-C условность фактически определяется int, а не реальными булевыми. Это связано с тем, что в C. нет такой вещи, как логический тип данных. Так что писать что-то вроде этого отлично работает в C:
if(5) printf("hello\n"); // prints hello
и, кроме того,
if(2029) printf("hello\n"); // also prints hello
В принципе, любой ненулевой int будет оцениваться как "истинный" в C. Вы комбинируете это с таблицами истинности для логического отрицания и равенства, и вы быстро понимаете, что:
(! someString) and (someString == nil)
для всех целей идентичны!
Итак, следующий логический вопрос: зачем предпочитать одну форму над другой? С чистой точки зрения C это было бы главным образом точкой стиля, но большинство (хороших) разработчиков выбрали тест равенства по нескольким причинам:
- Это ближе к тому, что вы пытаетесь выразить в коде. Вы
пытаясь проверить, нет ли переменной someString.
- Это более портативный. Языки, подобные Java, имеют настоящий булевский тип.
Вы не можете использовать обозначение помех для своих переменных или их NULL
определение. Использование равенства, в котором его необходимо, облегчает перенос
C на такие языки позже.
- Apple может изменить определение nil. Хорошо, они не будут! Но это
никогда не боится быть в безопасности!
Ответ 4
В вашем случае это означает одно и то же. Любой указатель, который не указывает на nil
, вернет YES
(true).
Обычно оператор восклицательной метки отрицает значение BOOL
.
Ответ 5
Если вы хотите проверить условие "foo is nil", вы должны сказать, что: foo == nil
.
Если вы хотите проверить логическое значение для ложности, !foo
в порядке, но лично я считаю, что скудный маленький восклицательный знак легко пропустить, поэтому я предпочитаю foo == NO
.
Написание хорошего кода - это явно передача вашего намерения не только компилятору, но и следующему программисту, который приходит (возможно, в будущем). В обоих случаях, чем более явным вы можете быть о том, что вы пытаетесь сделать, тем лучше.
Все, что в стороне, !
и ==nil
имеют одинаковый эффект во всех случаях, о которых я могу думать.
Ответ 6
!
- оператор отрицания. Если ваш объект не выделен, вы получите тот же результат из таблицы истинности, что и с операцией == nil
.
Но,! обычно больше используется для булевых операций.
if(!isFalse) {
//if isFalse == NO, then this operation evaluates to YES (true)
[self doStuff];
}
Когда вы используете !
для объекта типа !something
, он просто проверяет, указывает ли указатель на nil
, если он этого не делает, он возвращает true, и оператор if срабатывает.