Как разработчик Java, читающий документацию Apple по Objective-C 2.0: мне интересно, что означает « отправка сообщения на ноль », не говоря уже о том, насколько это действительно полезно. Взяв отрывок из документации:
В Какао есть несколько шаблонов, которые используют этот факт. Значение, возвращаемое из сообщения в nil, также может быть действительным:
- Если метод возвращает объект, любой тип указателя, любой целочисленный скаляр размера меньше или равный sizeof (void *), float, double, a long double или long long, то сообщение, отправленное в nil, возвращает 0 .
- Если метод возвращает структуру, как определено в Руководстве по вызову функций Mac OS X ABI, которая должна быть возвращена в регистрах, то сообщение, отправленное в nil, возвращает 0,0 для каждого поля в структуре данных. Другие типы данных структуры не будут заполняться нулями.
- Если метод возвращает что-либо, кроме вышеупомянутых типов значений, возвращаемое значение сообщения, отправленного в nil, не определено.
Неужели Java сделала мой мозг неспособным понять приведенное выше объяснение? Или мне не хватает чего-то, что сделало бы это таким же прозрачным, как стекло?
Я понимаю, что такое сообщения / получатели в Objective-C, я просто не понимаю, какой получатель есть nil
.
objective-c
Райан Делукки
источник
источник
Ответы:
Что ж, думаю, это можно описать на очень надуманном примере. Допустим, у вас есть метод на Java, который распечатывает все элементы в ArrayList:
Теперь, если вы вызовете этот метод так: someObject.foo (NULL); вы, вероятно, получите исключение NullPointerException, когда он попытается получить доступ к списку, в данном случае при вызове list.size (); Вы, вероятно, никогда не вызовете someObject.foo (NULL) с таким значением NULL. Однако вы могли получить свой ArrayList из метода, который возвращает NULL, если он сталкивается с какой-либо ошибкой, генерирующей ArrayList, например someObject.foo (otherObject.getArrayList ());
Конечно, у вас тоже будут проблемы, если вы сделаете что-то вроде этого:
Теперь в Objective-C у нас есть эквивалентный метод:
Теперь, если у нас есть следующий код:
у нас есть та же ситуация, в которой Java создаст исключение NullPointerException. Сначала будет осуществлен доступ к объекту nil по адресу [anArray count]. Однако вместо того, чтобы генерировать исключение NullPointerException, Objective-C просто вернет 0 в соответствии с приведенными выше правилами, поэтому цикл не будет выполняться. Однако, если мы настроим цикл на запуск заданное количество раз, то сначала мы отправим сообщение в anArray по адресу [anArray objectAtIndex: i]; Это также вернет 0, но поскольку objectAtIndex: возвращает указатель, а указатель на 0 равен nil / NULL, NSLog будет передаваться nil каждый раз в цикле. (Хотя NSLog - это функция, а не метод, он выводит (null), если передано nil NSString.
В некоторых случаях лучше иметь исключение NullPointerException, поскольку вы можете сразу сказать, что с программой что-то не так, но если вы не поймаете исключение, программа выйдет из строя. (В C попытка разыменовать NULL таким образом приводит к сбою программы.) В Objective-C это просто вызывает, возможно, некорректное поведение во время выполнения. Однако, если у вас есть метод, который не нарушает работу, если он возвращает 0 / nil / NULL / обнуленную структуру, то это избавляет вас от необходимости проверять, что объект или параметры равны нулю.
источник
myObject->iVar
он выйдет из строя, независимо от того, C с объектами или без них . (извините за могилу)->
это уже не операция Objective-C, а скорее общий C-ism.Сообщение для
nil
ничего не делает и возвращаетnil
,Nil
,NULL
,0
, или0.0
.источник
Все остальные сообщения верны, но, возможно, здесь важна концепция.
В вызовах методов Objective-C любая ссылка на объект, которая может принимать селектор, является допустимой целью для этого селектора.
Это сэкономит МНОГО от «является ли целевой объект типа X?» code - до тех пор, пока получающий объект реализует селектор, совершенно не имеет значения, какой это класс!
nil
это NSObject, который принимает любой селектор - он просто ничего не делает . Это также избавляет от большого количества кода «проверка на ноль, не отправлять сообщение, если истинно». (Концепция «если он это принимает, то реализует» - это также то, что позволяет вам создавать протоколы , которые в некотором роде похожи на интерфейсы Java: декларация о том, что если класс реализует указанные методы, то он соответствует протоколу.)Причина в том, чтобы исключить код обезьяны, который ничего не делает, кроме как радует компилятор. Да, вы получаете накладные расходы на вызов еще одного метода, но вы экономите время программиста , которое является гораздо более дорогим ресурсом, чем время процессора. Кроме того, вы устраняете из своего приложения больше кода и большую условную сложность.
Разъяснение для тех, кто проголосовал против: вы можете подумать, что это не лучший способ, но это то, как реализован язык, и это рекомендуемая идиома программирования в Objective-C (см. Стэнфордские лекции по программированию для iPhone).
источник
Это означает, что среда выполнения не выдает ошибки, когда objc_msgSend вызывается для указателя nil; вместо этого он возвращает некоторое (часто полезное) значение. Сообщения, которые могут иметь побочный эффект, ничего не делают.
Это полезно, потому что большинство значений по умолчанию более подходят, чем ошибка. Например:
Т.е., nil оказывается пустым массивом. Скрытие нулевой ссылки NSView ничего не делает. Удобно, а?
источник
В цитате из документации есть две отдельные концепции - возможно, было бы лучше, если бы в документации это было более ясно:
Первое, вероятно, здесь более уместно: как правило, возможность отправлять сообщения для
nil
упрощения кода - вам не нужно везде проверять нулевые значения. Каноническим примером, вероятно, является метод доступа:При отправке сообщения
nil
не были действительны, этот метод будет более сложным - Вы должны были бы иметь две дополнительные проверки для обеспеченияvalue
иnewValue
неnil
перед отправкой им сообщения.Последний пункт (значения, возвращаемые из сообщения
nil
, также обычно действительны), однако, добавляет эффект умножения к первому. Например:Этот код снова не требует проверки
nil
значений и течет естественно ...Все это говорит о том, что дополнительная гибкость, связанная с отправкой сообщений,
nil
требует определенных затрат. Существует вероятность того, что на каком-то этапе вы напишете код, который выйдет из строя из-за того, что вы не учли возможность того, что значение может бытьnil
.источник
От Greg Parker «S сайте :
При запуске LLVM Compiler 3.0 (Xcode 4.2) или новее
источник
Это означает, что часто не нужно везде проверять отсутствие объектов на предмет безопасности, в частности:
или, как уже отмечалось, все методы count и length возвращают 0, когда у вас есть значение nil, поэтому вам не нужно добавлять дополнительные проверки на nil повсюду:
или это:
источник
Не думайте о том, что «получатель ноль»; Я согласен, что это довольно странно. Если вы отправляете сообщение на nil, получателя нет. Вы просто никуда не отправляете сообщение.
Как с этим справиться - это философское различие между Java и Objective-C: в Java это ошибка; в Objective-C это не работает.
источник
Сообщения ObjC, которые отправляются в nil и возвращаемые значения которых имеют размер больше sizeof (void *), производят неопределенные значения на процессорах PowerPC. Кроме того, эти сообщения вызывают возвращение неопределенных значений в полях структур, размер которых превышает 8 байт на процессорах Intel. Винсент Гейбл прекрасно описал это в своей блоге.
источник
Я не думаю, что в других ответах это четко упоминалось: если вы привыкли к Java, вы должны иметь в виду, что, хотя Objective-C в Mac OS X имеет поддержку обработки исключений, это дополнительная языковая функция, которая может быть включается / выключается флагом компилятора. Я предполагаю, что этот дизайн «отправка сообщений в
nil
безопасное место» предшествует включению поддержки обработки исключений в язык и был сделан с той же целью: методы могут возвращаться,nil
чтобы указать на ошибки, и поскольку отправка сообщенияnil
обычно возвращаетnil
в свою очередь, это позволяет индикации ошибки распространяться по вашему коду, поэтому вам не нужно проверять ее при каждом сообщении. Вам нужно только проверить это в тех точках, где это важно. Я лично считаю, что распространение и обработка исключений - лучший способ достичь этой цели, но не все могут с этим согласиться. (С другой стороны, мне, например, не нравится требование Java о том, что вы должны объявлять, какие исключения может генерировать метод, что часто вынуждает вас синтаксически распространять объявления исключений по всему вашему коду; но это другое обсуждение.)Я опубликовал аналогичный, но более длинный ответ на связанный с этим вопрос «Требуется ли утверждение, что создание каждого объекта выполнено успешно в Objective C?» если вам нужны подробности.
источник
nil
возврат часто использовался для короткого замыкания цепочки в NO-op.C ничего не представляет как 0 для примитивных значений и NULL для указателей (что эквивалентно 0 в контексте указателя).
Objective-C строится на представлении C ничего, добавляя nil. nil - это объектный указатель ни на что. Хотя семантически отличны от NULL, они технически эквивалентны друг другу.
Недавно выделенные объекты NSObject начинают свою жизнь с их содержимым, установленным на 0. Это означает, что все указатели, которые объект имеет на другие объекты, начинаются с nil, поэтому нет необходимости, например, устанавливать self. (Association) = nil в методах инициализации.
Однако наиболее примечательным поведением nil является то, что ему могут отправляться сообщения.
В других языках, таких как C ++ (или Java), это приведет к сбою вашей программы, но в Objective-C вызов метода по nil возвращает нулевое значение. Это значительно упрощает выражения, так как избавляет от необходимости проверять ноль перед тем, как что-либо делать:
Осведомленность о том, как nil работает в Objective-C, позволяет этому удобству быть функцией, а не скрытой ошибкой в вашем приложении. Обязательно защитите себя от случаев, когда значения nil нежелательны, либо проверяя и возвращая на раннем этапе для молчаливого сбоя, либо добавляя NSParameterAssert для создания исключения.
Источник: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (отправка сообщения на ноль).
источник