Отправка сообщения nil в Objective-C



как разработчик Java, который читает документацию Apple Objective-C 2.0: интересно, что" отправка сообщения на ноль " означает-не говоря уже о том, как это на самом деле полезно. Взяв отрывок из документации:




есть несколько моделей в какао
вот и воспользуемся этим фактом. Этот
значение, возвращаемое из сообщения в ноль
также могут быть действительны:




  • если метод возвращает объект, любой тип указателя, любой целочисленный скаляр
    размером меньше или равным
    sizeof (void*), float, double, a
    длинный двойной, или долгое, затем
    сообщение, отправленное в nil, возвращает 0.

  • если метод возвращает структуру, как определено функцией Mac OS X ABI
    Руководство по вызову, которое будет возвращено в
    регистрируется, затем сообщение отправляется на ноль
    возвращает 0.0 для каждого поля
    структура данных. Другие данные структуры
    типы не будут заполнены нулями.

  • если метод возвращает что-либо, кроме вышеупомянутого значение
    вводит возвращаемое значение сообщения
    отправлено в ноль не определено.




сделал ли Java мой мозг неспособным грокнуть объяснение выше? Или есть что-то, чего мне не хватает, что сделало бы это таким же ясным, как стекло?



Я получаю представление о сообщениях / приемниках в Objective-C, я просто запутался в приемнике, который бывает nil.

597   11  

11 ответов:

Ну, я думаю, что это можно описать, используя очень надуманный пример. Допустим, у вас есть метод в Java, который выводит все элементы в ArrayList:

void foo(ArrayList list)
{
    for(int i = 0; i < list.size(); ++i){
        System.out.println(list.get(i).toString());
    }
}

теперь, если вы называете этот метод так: someObject.foo (NULL); вы, вероятно, получите исключение NullPointerException при попытке доступа к списку, в данном случае в вызове списка.size (); теперь вы, вероятно, никогда не вызовете someObject.foo (NULL) с таким значением NULL. Тем не менее, вы, возможно, получили ваш ArrayList из метода, который возвращает NULL, если он сталкивается с некоторой ошибкой, генерирующей 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 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 / нулевая структура, то это избавляет вас от необходимости проверять, чтобы убедиться, что объект или параметры равны нулю.

сообщение nil ничего не делает и возвращает nil,Nil,NULL,0 или 0.0.

все остальные сообщения верны, но, возможно, это концепция, которая здесь важна.

в вызовах метода Objective-C любая ссылка на объект, которая может принимать селектор, является допустимой целью для этого селектора.

Это экономит много "Является ли целевой объект типа X?"код - пока принимающий объект реализует селектор, он делает абсолютно никакой разницы какой это класс! nil является NSObject, который принимает любой селектор-это просто не do все что угодно. Это устраняет много" проверить на ноль, не отправлять сообщение, если true " код, а также. (Концепция" если он принимает его, он реализует его " также позволяет вам создавать протоколы, которые являются своего рода Java-интерфейсами: объявление о том, что если класс реализует указанные методы, то он соответствует протоколу.)

причина этого заключается в устранении кода обезьяны, который ничего не делает, кроме сохранения компилятора счастливый. Да, вы получаете накладные расходы еще одного вызова метода, но вы сохраняете программист времени, который является гораздо более дорогим ресурсом, чем процессорное время. Кроме того, вы устраняете больше кода и больше условной сложности из своего приложения.

уточнение для downvoters: вы можете подумать, что это не очень хороший способ, но это то, как реализуется язык, и это рекомендуемая идиома программирования В объективе-C (см. Программирование Стэнфордского iPhone лекции.)

это означает, что среда выполнения не выдает ошибку при вызове objc_msgSend для указателя nil; вместо этого она возвращает некоторое (часто полезное) значение. Сообщения, которые могут иметь побочный эффект ничего не делать.

Это полезно, потому что большинство значений по умолчанию являются более подходящими, чем ошибка. Например:

[someNullNSArrayReference count] => 0

т. е., nil кажется пустым массивом. Скрытие нулевой ссылки NSView ничего не делает. Удобно, а?

в цитате из документации есть две отдельные концепции - возможно, было бы лучше, если бы документация сделала это более ясным:

есть несколько моделей в какао, которые используют этот факт.

значение, возвращаемое из сообщения в nil, также может быть допустимым:

первое, вероятно, более актуально здесь: как правило, возможность отправлять сообщения в 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.

С Грег Паркер ' s сайт:

при запуске компилятора LLVM 3.0 (Xcode 4.2) или более поздней версии

Messages to nil with return type | return
Integers up to 64 bits           | 0
Floating-point up to long double | 0.0
Pointers                         | nil
Structs                          | {0}
Any _Complex type                | {0, 0}

это означает, что часто не нужно проверять наличие нулевых объектов везде для обеспечения безопасности-в частности:

[someVariable release];

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

if ( [myString length] > 0 )

или такой:

return [myArray count]; // say for number of rows in a table

Не думайте о том, что "приемник равен нулю"; я согласен, что и довольно странно. Если вы отправляете сообщение на nil, приемника нет. Ты просто посылаешь сообщение в никуда.

Как справиться с этим-это философское различие между Java и Objective-C: в Java это ошибка; в Objective-C это no-op.

сообщения ObjC, которые отправляются в nil и чьи возвращаемые значения имеют размер больше, чем sizeof(void*), производят неопределенные значения на процессорах PowerPC. Кроме того, эти сообщения приводят к возвращению неопределенных значений в полях структур, размер которых превышает 8 байт на процессорах Intel. Винсент Гейбл прекрасно описал это в своем блоге

Я не думаю, что какой-либо из других ответов упомянул об этом ясно: если вы привыкли к Java, вы должны иметь в виду, что в то время как Objective-C на Mac OS X имеет поддержку обработки исключений, это дополнительная функция языка, которая может быть включена/выключена с флагом компилятора. Я предполагаю, что это дизайн " отправка сообщений в nil безопасно " предшествует включению поддержки обработки исключений в языке и было сделано с аналогичной целью в виду: методы могут возвращать nil указать ошибки, и с момента отправки сообщения nil обычно возвращает nil в свою очередь, это позволяет индикации ошибок распространяться через ваш код, так что вам не придется проверять его на каждое сообщение. Вы только должны проверить его в точках, где это имеет значение. Я лично думаю, что распространение исключений и обработка-лучший способ решить эту задачу, но не все могут согласиться с этим. (С другой стороны, мне, например, не нравится требование Java о том, что вам нужно объявить, какие исключения a метод может бросить, что часто заставляет вас синтаксически распространять объявления исключений по всему коду; но это другое обсуждение.)

я опубликовал аналогичный, но более длинный ответ на соответствующий вопрос "является ли утверждение, что каждое создание объекта преуспело, необходимым в объективе C?" если вы хотите более детально.

C не представляет ничего как 0 для примитивных значений и NULL для указателей (что эквивалентно 0 в контексте указателя).

Objective-C строится на представлении C ничего, добавляя nil. nil-это указатель объекта на ничто. Хотя они семантически отличаются от NULL, они технически эквивалентны друг другу.

недавно выделенные NSObjects начинают жизнь с их содержимым, установленным в 0. Это означает, что все указатели этого объекта на другие объекты начинаются с нуля, поэтому нет необходимости, например, устанавливать себя.(ассоциация) = nil in init методы.

наиболее заметным поведением nil, однако, является то, что он может отправлять сообщения.

в других языках, таких как C++ (или Java), это приведет к сбою вашей программы, но в Objective-C вызов метода на nil возвращает нулевое значение. Это значительно упрощает выражения, так как устраняет необходимость проверять nil перед тем, как что-либо делать:

// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }

// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }

быть в курсе как nil работает в Objective-C позволяет этому удобству быть функцией, а не скрытой ошибкой в вашем приложении. Убедитесь в том, чтобы защитить от случаев, когда значения nil нежелательны, либо проверяя и возвращая рано, чтобы беззвучно завершиться ошибкой, либо добавляя NSParameterAssert для создания исключения.

источник: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (отправка Сообщение на ноль).

Comments

    Ничего не найдено.