"Вызов метода" ИЛИ "отправка сообщения" в Задаче C

В C или любом языке, основанном на ECMAscript, вы "вызываете публичный метод или функцию" для объекта. Но в документации для Objective C нет открытых вызовов методов, только отправка сообщений.

Есть ли что-то неправильное в том, что когда вы "отправляете сообщение" в ObjC, вы на самом деле "вызываете публичный метод для объекта"?

5 ответов

Решение

Теоретически они разные.

Практически не так много.

Они отличаются тем, что в Objective-C объекты могут выбрать не отвечать на сообщения или пересылать сообщения другим объектам или чему-либо еще. В таких языках, как C, вызовы функций в действительности просто переходят в определенную область памяти и выполняют код. Там нет динамического поведения.

Однако в стандартных случаях использования, когда вы отправляете сообщение объекту, обычно вызывается метод, представленный в сообщении. Поэтому примерно в 99% случаев отправка сообщения приводит к вызову метода. Поэтому мы часто говорим "вызвать метод", когда на самом деле имеем в виду "отправить сообщение". Практически, они почти всегда одинаковы, но они не должны быть такими.

Некоторое время назад я философствовал по этой теме и писал о ней в блоге: http://davedelong.tumblr.com/post/58428190187/an-observation-on-objective-c

редактировать

Чтобы прямо ответить на ваш вопрос, обычно нет ничего неправильного в том, чтобы сказать "вызов метода" вместо "отправки сообщения". Тем не менее, важно понимать, что существует очень существенная разница в реализации.

(И, кроме того, мое личное предпочтение - сказать "вызвать метод для объекта")

Из-за динамической отправки сообщений Objective-C отправка сообщений фактически отличается от вызова функции C или метода C++ (хотя в конечном итоге будет вызвана функция C). Сообщения отправляются через селекторы получающему объекту, который либо отвечает на сообщение, вызывая IMP (указатель на функцию C) или путем пересылки сообщения его суперклассу. Если ни один класс в цепочке наследования не отвечает на сообщение, генерируется исключение. Также возможно перехватить сообщение и переслать его в совершенно другой класс (вот что NSProxy подклассы делают).

При использовании Objective-C нет большой разницы между отправкой сообщений и вызовом метода в стиле C++, но есть несколько практических последствий системы передачи сообщений, о которых я знаю:

  1. Поскольку обработка сообщений происходит во время выполнения, а не во время компиляции, нет способа узнать, отвечает ли класс на какое-либо конкретное сообщение во время компиляции. Вот почему вы обычно получаете предупреждения компилятора вместо ошибок, когда вы, например, неправильно пишете метод.
  2. Вы можете безопасно отправить любое сообщение nil, учитывая такие идиомы, как [foo release] не беспокоясь о проверке на NULL.
  3. Как говорит @CrazyJugglerDrummer, диспетчеризация сообщений позволяет отправлять сообщения множеству объектов одновременно, не беспокоясь о том, будут ли они на них отвечать. Это позволяет использовать неофициальные протоколы и отправлять сообщения всем объектам в контейнере.
  4. Я не уверен на 100% в этом, но я думаю, что категории (добавление методов к уже существующим классам) стали возможными благодаря динамической отправке сообщений.
  5. Отправка сообщения позволяет пересылать сообщения (например, с NSProxy подклассы).
  6. Отправка сообщений позволяет вам делать интересные низкоуровневые взломы, такие как метод swizzling (обмен реализациями методов во время выполнения).

Нет, в этом нет ничего плохого. Они называются сообщениями, потому что они представляют собой слой абстракции над функциями. Частично это происходит из системы типов Objective C. Лучшее понимание сообщений помогает:

полный источник в википедии (я выбрал некоторые из наиболее актуальных вопросов)

Внутренние имена функции редко используются напрямую. Обычно сообщения преобразуются в вызовы функций, определенные в библиотеке времени выполнения Objective C. Во время соединения не обязательно известно, какой метод будет вызван, потому что класс получателя (объект, отправляющий сообщение) не должен быть известен до времени выполнения.

из той же статьи:

Модель объектно-ориентированного программирования Objective-C основана на передаче сообщений экземплярам объекта. В Objective-C никто не вызывает метод; один отправляет сообщение. Объект, к которому направлено сообщение - получатель - не обязательно отвечает на сообщение, а если нет, то просто вызывает исключение. Программирование в стиле Smalltalk позволяет сообщениям не реализовываться, а метод разрешается к его реализации во время выполнения. Например, сообщение может быть отправлено в коллекцию объектов, на которые, как ожидается, будут реагировать только некоторые, не опасаясь возникновения ошибок во время выполнения. (Платформа Какао использует это преимущество, поскольку все объекты в приложении Какао отправляются сообщением awakeFromNib: при запуске приложения. Объекты могут отвечать, выполняя любую инициализацию, требуемую при запуске.) Передача сообщений также не требует определения объекта во время компиляции.

При вызове функции C компилятор заменяет селектор вызовом функции, и выполнение переходит в ответ на вызов функции.

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

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

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

Другие вопросы по тегам