! 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 срабатывает.