Как известно, в Objective C управлять видимостью методов, в отличие от видимости переменных, нельзя – все методы являются публичными. Насколько я понимаю, такое поведение имеет корни в модели “отправки сообщений”, которая тянется из Smalltalk. Любой объект отвечает на любое сообщение, которое он способен распознать и обработать. Технически, вызов метода представляет собой вызов функции objc_msgSend, принимающей указатель на объект, селектор и дополнительные параметры метода, и нет никакой возможности для среды выполнения определить, в каком контексте находится метод, кроме затратных, вроде передвижения по стеку и анализа лежащего в регистре self.

Ладно, нет так нет, нам от технической возможности или невозможности особо ни горячо ни холодно. Но ведь хочется! Хочется сделать нормальную инкапсуляцию, выстраивая грамотные иерархии наследования для исключения дублирования и возможности расширения, и чтобы не было соблазна ползать по внутренним методам, дергая за кишочки объектов. Ведь все ошибки в программах – это вина исключительно программистов.

Да, областей видимости действительно нет, но их можно имитировать, и я хочу показать, как.

Имитация private области видимости может осуществляться двумя различными путями.

Путь первый – это определение private функций в @implementation .. @end самого класса. Любая функция, будучи определена там, становится доступной для вызова ниже по коду без каких-либо предупреждений компилятора о том, что объект, возможно, не отвечает на данное сообщение. Путь простой, но заставляет думать о том, куда поместить ту или иную функцию, ведь от ее местоположения зависит, будет ли выдаваться предупреждение или нет.

Но есть и второй путь. Мы воспользуемся категориями. Мне он кажется более удобным и я применяю именно его.

Для имитации private методов с помощью категорий, нужно в .m файле, перед @implementation добавить безымянную категорию. Для класса Something ее определение будет выглядеть как @interface Something () ... @end. Стоит обратить особое внимание на пустые скобки – они показывают, что мы определяем именно безымянную категорию. После этого, мы можем добавлять в категорию методы, которые будут для нас считаться private. За счет того, что категория безымянная, имплементация данных методов может находиться рядом с имплементацией основных методов в разделе @implementation .. @end и нет необходимости создавать отдельные разделы для имплементации категорий. А за счет того, что она находится в .m файле, которые никто не подключает через #import (вы ведь их не подключаете, да?), видимость методов для автодополнения ограничена текущим файлом. Конечно, послать объекту это сообщение извне все равно возможно, но от случайного вызова вы точно застрахованы.

Область видимости типа protected имитировать сложнее, но тоже возможно, если воспользоваться идеей насчет категорий. Для имитации видимости @protected создается отдельны файл с расширением .m, в котором описывается категория тем же методом, который мы использовали для видимости типа private. После этого, вы просто подключаете файл через директиву #import в основном .m-файле с имплементацией и пишете тела методов. После этого, подключением основного .h-файла вы подключаете публичные методы, а если вам нужно работать с защищенными в иерархии наследования, то вы в .m файле наследника подключаете .m-файл с безымянной категорией, описывающей защищенные методы.

Поясню последнее на примере. Допустим, у нас есть класс Student, у которого есть публичный метод doHomework и защищенный homeworkDone, который вызывается в конце doHomework, и есть наследник класса Student – класс SmartStudent, у которого защищенный метод должен быть переопределен. Такая вот синтетика.

Определяем класс Student. Создадим три файла – Student.h, Student.m и Student.ProtectedMethods.h.

Student.h

Student.ProtectedMethods.h

Student.m

Определяем класс SmartStudent. Создадим два файла – SmartStudent.h, SmartStudent.m

SmartStudent.h

SmartStudent.m

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

Share →

3 Responses to Имитация private и protected методов в Objective C.

  1. UndeadKing says:

    Странный путь объявления приватов. Подключил м-ку или х-шку – вот тебе и все приваты, кончились…

    • bober_maniac says:

      Дык имитация же.

      • UndeadKing says:

        Предлагаю хардкорный вариант с ползанием по колл-стеку. Для приватов покатит, для протектедов – не очень =)

Leave a Reply

Войти с помощью: 

Your email address will not be published. Required fields are marked *

PageLines