Для методов Objective-C общая практика заключается в том, чтобы поместить методы, которые вы хотите выставить в разделе заголовка файла @interface
, поэтому другой код может включать только .h и знать, как взаимодействовать с вашим кодом. «Ленивая декларация» на основе заказа работает точно так же, как функции на C - вы не должны объявить прототип метода, если у вас нет зависимости, которая не может быть разрешена путем заказа, но вы можете добавить прототипы методов внутри @implementation
, если необходимо.
Итак, да, вы на правильном пути. Не повторяйте прототип метода для унаследованных методов - компилятор находит его в заголовочном файле родителя. Методы делегатов могут быть определены как прототипы в категории (прикреплены к классу) и реализованы по желанию, но делегату не нужно предоставлять прототип метода, поскольку он уже определен. (Он все еще может, если он хочет для ясности и т. Д.)
Поскольку вы только изучаете Objective-C, остальная часть этого ответа намного более подробно, чем вы просили. Вы были предупреждены. ;-)
Когда вы статически тип переменной (например MyClass*
вместо id
) компилятор предупредит вас, когда вы пытаетесь вызвать метод, который класс не рекламируют, что он реализует, делает ли это или нет. Если вы динамически вводите переменную, компилятор не остановит вас на то, что вы хотите, и вы получите только ошибки времени выполнения, если вы вызовете что-то, что не существует. Что касается языка, вы можете вызвать любой метод, который класс реализует без ошибок во время выполнения - нет способа ограничить, кто может вызвать метод.
Лично я считаю, что это на самом деле хорошо. Мы так привыкли к инкапсуляции и защите нашего кода из другого кода, что мы иногда относимся к вызывающему как коварный злоумышленник, а не к заслуживающим доверия коллеге или клиенту. Я считаю, что очень приятно кодировать мышление «ты делаешь свою работу, а я делаю свое», где все уважают границы и заботятся о своей собственной. Вы могли бы сказать, что «отношение» Objective-C - это доверие сообщества, а не строгое соблюдение. Например, я рад помочь любому, кто приходит на мой рабочий стол, но будет очень раздражен, если кто-то испортит мои вещи или пошевелится вокруг, не спросив. Хорошо продуманный код не должен быть параноидальным или социопатическим, он просто должен хорошо работать вместе. :-)
При этом существует много подходов к структурированию ваших интерфейсов, в зависимости от уровня детализации, который вы хотите/нуждаетесь в разоблачении интерфейсов для пользователей. Любые методы, которые вы объявляете в публичном заголовке, являются, по существу, честной игрой для тех, кто их использует. Объявление метода скрытия немного напоминает блокировку вашего автомобиля или дома - это, вероятно, не уберет всех, но (1) это «держит честных людей честными», не соблазняя их чем-то, с чем им не следует возиться, и (2) кто-нибудь, кто делает входите, конечно, знает, что они не должны были и не могут действительно жаловаться на негативные последствия.
Ниже приведены некоторые соглашения, которые я использую для именования файлов, и что происходит в каждом файле - начиная с файла .m внизу, каждый файл содержит тот, что над ним. (Использование строгой последовательности включений предотвратит такие вещи, как дубликаты предупреждений символов.) Некоторые из этих уровней применимы только к более крупным многоразовым компонентам, таким как каркасы Cocoa. Адаптируйте их в соответствии с вашими потребностями и используйте все, что вам подходит.
MyClass.h
- Public API (Application Programming Interface)
MyClass_Private.h
- компания-внутренний SPI (System Programming Interface)
MyClass_Internal.h
- Проект-внутренний IPI (Внутренний интерфейс программирования)
MyClass.m
- реализация, как правило, из всех заявлений API/SPI/IPI
MyClass_Foo.m
- Дополнительная реализация, например, для категорий
API предназначен для всех пользователей и поддерживается общедоступно (обычно в Foo.framework/Headers
). SPI предоставляет дополнительные функции для внутренних клиентов вашего кода, но при том понимании, что поддержка может быть ограничена, и интерфейс может быть изменен (обычно в Foo.framework/PrivateHeaders
). IPI состоит из деталей, специфичных для реализации, которые никогда не должны использоваться вне самого проекта, и эти заголовки вообще не включены в структуру. Любой, кто хочет использовать вызовы SPI и IPI, делает это на свой страх и риск и обычно в ущерб, когда изменения нарушают их код. :-)
+1. Благодарим за то, что нам не нужны стальные пластины, чтобы сотрудники не путались с нашими кубами, и нам не нужно требовать языкового принуждения, чтобы они не вмешивались во внутренние структуры данных. Если нам это нужно, нам нужны лучшие коллеги. Предупреждения компилятора важны (наряду с -Werror), точно так же, как маленькие этикетки на еде в холодильнике, говорящие «это мое, не ешьте». ObjC - это язык для взрослых. Вы следуете правилам, даже когда ваша мама (компилятор) не заставляет вас. И поэтому вам не нужно находить трюки вокруг компилятора, как вы часто это делаете на других языках. –
+1 Отличный ответ! :) –
Надеюсь, я не пропущу точку, но часто задавался вопросом, можно ли скрыть переменные-члены с помощью этой структуры многоуровневых API или все еще нужно объявить в MyClass.h? – Akusete