Вызов метода или отправка сообщения в Objective-C
В C или любом языке на основе ECMAScript вы «вызываете публичный метод или функцию» у объекта. Однако в документации по Objective-C нет упоминания о вызовах публичных методов, а только о передаче сообщений.
Есть ли что-то неправильное в том, чтобы считать, что когда вы «отправляете сообщение» в Objective-C, вы на самом деле «вызываете публичный метод у объекта»?
3 ответ(ов)
Теоретически они разные.
Практически — не так уж и сильно.
Разница заключается в том, что в Objective-C объекты могут не реагировать на сообщения или перенаправлять их другим объектам и так далее. В языках, таких как C, вызовы функций по сути представляют собой переход к определенному участку памяти и выполнение кода. Здесь нет динамического поведения.
Однако в стандартных случаях, когда вы отправляете сообщение объекту, метод, соответствующий этому сообщению, обычно будет вызван. Таким образом, примерно в 99% случаев отправка сообщения приводит к вызову метода. Поэтому мы часто говорим "вызвать метод", когда на самом деле имеем в виду "отправить сообщение". Таким образом, на практике они почти всегда одно и то же, но не обязательно.
Недавно я размышлял на эту тему и написал об этом в блоге: ссылка
Редактирование
Чтобы прямо ответить на ваш вопрос, обычно нет ничего плохого в том, чтобы говорить "вызвать метод" вместо "отправить сообщение". Однако важно понимать, что между ними существует довольно значительная разница в реализации.
(К слову, лично мне больше нравится говорить "вызывать метод у объекта".)
Из-за динамической отправки сообщений в Objective-C, процесс отправки сообщения отличается от вызова функции на C или метода на C++ (хотя в конечном итоге будет вызвана функция C). Сообщения отправляются через селекторы объекту-получателю, который либо отвечает на сообщение, вызывая IMP
(указатель на функцию C), либо перенаправляет сообщение своему суперклассу. Если ни один класс в цепочке наследования не отвечает на сообщение, генерируется исключение. Также возможно перехватить сообщение и перенаправить его в совершенно другой класс (именно это делают подклассы NSProxy
).
При использовании Objective-C нет значительной разницы между отправкой сообщений и вызовом методов в стиле C++, но есть несколько практических особенностей системы передачи сообщений, о которых мне известно:
- Поскольку обработка сообщений происходит во время выполнения, а не на этапе компиляции, нет способа на этапе компиляции узнать, отвечает ли класс на конкретное сообщение. Поэтому обычно вы получаете предупреждения компилятора вместо ошибок, если, например, вы ошиблись в написании метода.
- Вы можете безопасно отправить любое сообщение
nil
, что позволяет использовать идиомы типа[foo release]
без беспокойства о проверке на NULL. - Как упоминает @CrazyJugglerDrummer, диспетчеризация сообщений позволяет вам отправлять сообщения множеству объектов одновременно, не беспокоясь о том, отреагируют ли они на них. Это позволяет использовать неформальные протоколы и отправлять сообщения всем объектам в контейнере.
- Я не на 100% уверен в этом, но думаю, что категории (добавление методов к уже существующим классам) стали возможны благодаря динамической диспетчеризации сообщений.
- Отправка сообщений позволяет производить перенаправление сообщений (например, с помощью подклассов
NSProxy
). - Отправка сообщений также позволяет заниматься интересными низкоуровневыми трюками, такими как свопинг методов (обмен реализацией методов во время выполнения).
В языке C при вызове функции компилятор заменяет селектор вызовом функции, и выполнение переходит к данной функции.
В Objective-C методы динамически связываются с сообщениями, что означает, что имена методов разрешаются на реализации во время выполнения. В частности, объект проверяется во время выполнения, чтобы определить, содержит ли он указатель на реализацию для данного селектора.
В результате, Objective-C позволяет загружать и связывать новые классы и категории во время работы, а также применять такие техники, как свизлинг, категории, прокси-объекты и другие. Ничего подобного невозможно в C.
Как сопоставить любой символ на нескольких строках в регулярном выражении?
Где найти документацию по форматированию даты в JavaScript?
Как проверить, содержит ли массив строку в TypeScript?
Ссылка и выполнение внешнего JavaScript-файла, размещенного на GitHub
Как остановить Babel от трансформации 'this' в 'undefined' и добавления "use strict"