Я видел несколько стратегий для объявления получастных методов в Objective-C , но, похоже, нет способа сделать действительно частный метод. Я принимаю это. Но почему это так? Каждое объяснение, которое я, по сути, говорит: «Вы не можете этого сделать, но вот примерное приближение».
Есть несколько ключевых слова применительно к ivars
(участникам) , которые контролируют сферу их применения, например @private
, @public
, @protected
. Почему это нельзя сделать и для методов? Похоже, что среда выполнения должна иметь возможность поддерживать. Есть ли какая-то основная философия, которую мне не хватает? Это умышленно?
objective-c
objective-c-runtime
Роб Джонс
источник
источник
Ответы:
Ответ ... ну ... простой. Фактически, простота и последовательность.
Objective-C является чисто динамическим в момент отправки метода. В частности, отправка каждого метода проходит через ту же точку разрешения динамического метода, что и отправка любого другого метода. Во время выполнения каждая реализация метода имеет одно и то же представление, и все API, предоставляемые средой выполнения Objective-C, которые работают с методами и селекторами, работают одинаково для всех методов.
Как многие ответили (как здесь, так и в других вопросах), поддерживаются частные методы времени компиляции; если класс не объявляет метод в своем общедоступном интерфейсе, то этот метод также может не существовать в отношении вашего кода. Другими словами, вы можете достичь всех желаемых комбинаций видимости во время компиляции, правильно организовав свой проект.
Дублирование одной и той же функциональности во время выполнения не дает особых преимуществ. Это добавило бы огромной сложности и накладных расходов. И даже при всей этой сложности это все равно не помешает всем, кроме самых случайных разработчиков, выполнять ваши якобы «частные» методы.
Однако это подорвало бы чистую динамическую природу языка. Отправка каждого метода больше не будет проходить через идентичный механизм отправки. Вместо этого вы окажетесь в ситуации, когда большинство методов ведут себя одинаково, а небольшая горстка - просто разные.
Это выходит за рамки среды выполнения, поскольку в Какао есть много механизмов, построенных на основе последовательного динамизма Objective-C. Например, и кодирование ключевого значения, и наблюдение ключевого значения должны быть либо очень сильно изменены для поддержки частных методов - скорее всего, путем создания уязвимой лазейки - либо частные методы будут несовместимы.
источник
Среда выполнения могла бы это поддерживать, но стоимость была бы огромной. Каждый отправленный селектор необходимо проверить на предмет того, является ли он частным или открытым для этого класса, или каждый класс должен будет управлять двумя отдельными таблицами диспетчеризации. Это не то же самое для переменных экземпляра, потому что этот уровень защиты выполняется во время компиляции.
Кроме того, среде выполнения необходимо будет проверить, что отправитель личного сообщения принадлежит к тому же классу, что и получатель. Вы также можете обойти частные методы; если используется класс
instanceMethodForSelector:
, он может передать возвращаемоеIMP
любому другому классу , чтобы он мог напрямую вызвать частный метод.Частные методы не могли обойти отправку сообщения. Рассмотрим следующий сценарий:
У класса
AllPublic
есть общедоступный метод экземпляраdoSomething
Другой класс
HasPrivate
имеет метод частного экземпляра, также называемыйdoSomething
Вы создаете массив, содержащий любое количество экземпляров обоих
AllPublic
иHasPrivate
У вас есть следующий цикл:
Если вы запускали эту петлю изнутри
AllPublic
, среда выполнения придется остановить вас посылатьdoSomething
наHasPrivate
случаях, однако этот цикл будет использоваться , если он был внутриHasPrivate
класса.источник
Ответы, опубликованные до сих пор, хорошо отвечают на вопрос с философской точки зрения, поэтому я собираюсь сформулировать более прагматическую причину: что можно получить, изменив семантику языка? Достаточно просто эффективно «скрыть» частные методы. В качестве примера представьте, что у вас есть класс, объявленный в файле заголовка, например:
Если вам нужны «частные» методы, вы также можете поместить это в файл реализации:
Конечно, это не совсем то же самое, что частные методы C ++ / Java, но фактически достаточно близко, так зачем менять семантику языка, а также компилятор, среду выполнения и т. Д., Чтобы добавить функцию, которая уже эмулирована в приемлемом путь? Как отмечалось в других ответах, семантика передачи сообщений - и их зависимость от отражения во время выполнения - сделает обработку «частных» сообщений нетривиальной.
источник
Самое простое решение - просто объявить некоторые статические функции C в ваших классах Objective-C. Они имеют только область видимости файла в соответствии с правилами C для ключевого слова static, и поэтому они могут использоваться только методами этого класса.
Никакой суеты.
источник
Да, это можно сделать, не влияя на время выполнения, используя технику, уже используемую компилятором (-ами) для обработки C ++: изменение имени.
Этого не было сделано, потому что не было установлено, что это решит некоторые значительные трудности в пространстве проблем кодирования, которые другие методы (например, префикс или подчеркивание) могут в достаточной степени обойти. IOW, вам нужно больше боли, чтобы преодолеть укоренившиеся привычки.
Вы можете внести исправления в clang или gcc, которые добавляют частные методы к синтаксису и генерируют искаженные имена, которые он сам распознает во время компиляции (и сразу же забывает). Тогда другие участники сообщества Objective-C смогут определить, стоит ли это на самом деле или нет. Вероятно, так будет быстрее, чем пытаться убедить разработчиков.
источник
По сути, это связано с формой передачи сообщений в Objective-C для вызовов методов. Любое сообщение может быть отправлено любому объекту, и объект сам выбирает, как ему ответить. Обычно он отвечает, выполняя метод, названный в честь сообщения, но он может отвечать и другими способами. Это не делает частные методы полностью невозможными - Ruby делает это с похожей системой передачи сообщений - но делает их несколько неудобными.
Даже реализация частных методов в Ruby немного сбивает с толку людей из-за своей странности (вы можете отправить объекту любое сообщение, которое вам нравится, кроме тех, что указаны в этом списке !). По сути, Ruby заставляет его работать, запрещая вызов частных методов с явным получателем. В Objective-C это потребует еще большей работы, поскольку в Objective-C такой возможности нет.
источник
Это проблема со средой выполнения Objective-C. Хотя C / C ++ компилируется в нечитаемый машинный код, Objective-C по-прежнему поддерживает некоторые удобочитаемые атрибуты, такие как имена методов в виде строк . Это дает Objective-C возможность выполнять функции отражения .
РЕДАКТИРОВАТЬ: будучи рефлексивным языком без строгих частных методов, Objective-C становится более «питоническим» в том смысле, что вы доверяете другим людям, использующим ваш код, а не ограничиваете методы, которые они могут вызывать. Использование соглашений об именах, таких как двойное подчеркивание, предназначено для того, чтобы скрыть ваш код от обычного клиентского кодировщика, но не остановит кодировщиков, нуждающихся в более серьезной работе.
источник
В зависимости от интерпретации вопроса есть два ответа.
Первый - скрыть реализацию метода от интерфейса. Обычно это используется с категорией без названия (например
@interface Foo()
). Это позволяет объекту отправлять эти сообщения, но не другие, хотя одно из них все же может случайно отменить (или иначе).Второй ответ, при условии, что речь идет о производительности и встраивании, возможен, но вместо этого как локальная функция C. Если вам нужен
NSString *arg
метод 'private foo ( )', вы должны сделатьvoid MyClass_foo(MyClass *self, NSString *arg)
и вызвать его как функцию C, напримерMyClass_foo(self,arg)
. Синтаксис отличается, но он действует с разумными характеристиками производительности частных методов C ++.Хотя это дает ответ на вопрос, я должен отметить, что категория без имени является гораздо более распространенным способом сделать это в Objective-C.
источник
Objective-C не поддерживает частные методы, потому что они ему не нужны.
В C ++ каждый метод должен быть виден в объявлении класса. У вас не может быть методов, которые не может видеть кто-то, включая файл заголовка. Поэтому, если вам нужны методы, которые код вне вашей реализации не должен использовать, у вас нет выбора, компилятор должен предоставить вам какой-то инструмент, чтобы вы могли сказать ему, что метод не должен использоваться, это ключевое слово «private».
В Objective-C у вас могут быть методы, которых нет в файле заголовка. Таким образом, вы очень легко достигнете той же цели, не добавляя метод в файл заголовка. Нет необходимости в частных методах. Objective-C также имеет то преимущество, что вам не нужно перекомпилировать каждого пользователя класса, потому что вы изменили частные методы.
Например, доступны переменные, которые вы раньше объявляли в файле заголовка (больше нет), @private, @public и @protected.
источник
Здесь отсутствует ответ: поскольку частные методы - плохая идея с точки зрения эволюционируемости. Может показаться хорошей идеей сделать метод закрытым при его написании, но это форма раннего связывания. Контекст может измениться, и более поздний пользователь может захотеть использовать другую реализацию. Немного провокационно: «Agile-разработчики не используют частные методы»
В некотором смысле, как и Smalltalk, Objective-C предназначен для взрослых программистов. Мы ценим знание того, каким должен быть интерфейс, по мнению исходного разработчика, и берем на себя ответственность за устранение последствий, если нам потребуется изменить реализацию. Так что да, это философия, а не реализация.
источник