Когда я определяю методы Objective-C?
-
06-07-2019 - |
Вопрос
Я изучаю Objective-C и имею опыт работы с C/C++.
В объектно-ориентированном C++ вам всегда необходимо объявлять метод перед его определением (реализацией), даже если он объявлен в родительском классе.
В процедурном стиле C, IIRC, вы можете просто определить функцию, если она вызывается только из чего-то другого в той же единице компиляции (т.тот же файл), который появился позже в файле (ну, при условии, что вы не объявите его где-либо еще с помощью «extern»).
Теперь, в Objective-C, кажется, что вам нужно объявлять селекторы в заголовочном файле только в том случае, если они будут использоваться чем-то внешним, и что вы можете прекрасно создавать селекторы в своем .m-файле и вызывать их внутри файл .m.Кроме того, похоже, что методы делегата или унаследованные методы никогда не определяются (пере)определяются.
Я на правильном пути?Когда вам нужно определить селектор в Objective-C?
Решение
Для методов Objective-C общепринятой практикой является размещение методов, которые вы хотите предоставить, в @interface
раздел заголовочного файла, чтобы другой код мог включать только расширение .h и знать, как взаимодействовать с вашим кодом.«Отложенное объявление» на основе порядка работает так же, как функции в C. придется объявляйте прототип метода, если у вас нет зависимости, которую нельзя разрешить путем упорядочивания, но вы можете добавлять прототипы методов внутри @implementation
если нужно.
Так что да, вы на правильном пути.Не повторяйте прототип метода для унаследованных методов — компилятор находит его в заголовочном файле родительского метода.Методы делегата могут быть определены как прототипы в категории (прикреплены к классу) и реализованы по желанию, но делегату не требуется предоставлять прототип метода, поскольку он уже определен.(Он все еще может, если захочет, для ясности и т. д.)
Поскольку вы только изучаете Objective-C, остальная часть этого ответа гораздо более подробна, чем вы просили.Вы были предупреждены.;-)
Когда вы статически вводите переменную (например, MyClass*
вместо id
) компилятор предупредит вас, когда вы попытаетесь вызвать метод, который класс не объявляет о своей реализации, независимо от того, реализует он это или нет.Если вы динамически вводите переменную, компилятор не будет мешать вам вызывать все, что захотите, и вы получите ошибки во время выполнения только в том случае, если вы вызовете что-то, чего не существует.Что касается языка, вы можете вызвать любой метод, реализуемый классом, без ошибок во время выполнения — невозможно ограничить круг лиц, которые могут вызывать метод.
Лично я считаю, что это на самом деле хорошо.Мы настолько привыкли к инкапсуляции и защите нашего кода от другого кода, что иногда относимся к вызывающему абоненту как к коварному злодею, а не как к заслуживающему доверия коллеге или клиенту.Я считаю, что довольно приятно писать код с мышлением «вы делаете свою работу, а я — свою», когда каждый уважает границы и заботится о своем.Вы могли бы сказать, что «отношение» Objective-C основано на доверии сообщества, а не на строгом принуждении.Например, я рад помочь любому, кто подходит ко мне на стол, но меня бы очень раздражало, если бы кто-то испортил мои вещи или передвинул вещи без моей просьбы.Хорошо спроектированный код не обязательно должен быть параноиком или социопатом, он просто должен хорошо работать вместе.:-)
Тем не менее, существует множество подходов к структурированию ваших интерфейсов, в зависимости от уровня детализации, который вам нужен/нужен при предоставлении интерфейсов пользователям.Любые методы, которые вы объявляете в общедоступном заголовке, по сути являются честной игрой, которую может использовать каждый.Сокрытие объявлений методов немного похоже на запирание машины или дома — оно, вероятно, не защитит всех, но (1) оно «сохраняет честность честных людей», не соблазняя их чем-то, с чем им не следует связываться, и (2 ) любой, кто делает войти, наверняка будут знать, что им этого делать не следовало, и не смогут жаловаться на негативные последствия.
Ниже приведены некоторые соглашения, которые я использую для именования файлов, и то, что содержится в каждом файле — начиная с файла .m внизу, каждый файл включает в себя файл над ним.(Использование строгой цепочки включений предотвратит такие вещи, как предупреждения о дублировании символов.) Некоторые из этих уровней применимы только к более крупным компонентам многократного использования, таким как платформы Cocoa.Адаптируйте их в соответствии со своими потребностями и используйте любые имена, которые вам подходят.
MyClass.h
— Публичный API (интерфейс прикладного программирования)MyClass_Private.h
— Внутренний SPI (интерфейс системного программирования) компании.MyClass_Internal.h
— Внутренний IPI проекта (внутренний программный интерфейс)MyClass.m
— Реализация, как правило, всех деклараций API/SPI/IPI.MyClass_Foo.m
— Дополнительная реализация, например для категорий
API предназначен для использования всеми и поддерживается публично (обычно в Foo.framework/Headers
).SPI предоставляет дополнительную функциональность для внутренних клиентов вашего кода, но с учетом того, что поддержка может быть ограничена, а интерфейс может быть изменен (обычно в Foo.framework/PrivateHeaders
).IPI состоит из деталей, специфичных для реализации, которые никогда не следует использовать вне самого проекта, и эти заголовки вообще не включены в структуру.Любой, кто решает использовать вызовы SPI и IPI, делает это на свой страх и риск и обычно себе во вред, когда изменения нарушают его код.:-)
Другие советы
Объявление методов в заголовочном файле остановит только предупреждения компилятора.Objective-C — это динамический язык, поэтому вы можете вызвать метод (отправить сообщение) объекту независимо от того, объявлен ли этот метод снаружи.
Кроме того, если вы определите метод в файле .m над любым кодом, который его вызывает (ленивое объявление), то это не будет генерировать никаких предупреждений.Однако применимо то же самое: вы можете отправить сообщение объекту без его объявления.
Конечно — это значит, что в Objective-C нет приватных методов.Можно вызвать любой метод, реализуемый классом.
Личное предпочтение.Если это общедоступный метод (т.е. используемый извне).объявите это в .h и определите в .m.Если вы хотите ограничить его видимость или хотя бы указать, что это частный метод, используйте расширения категорий/классов в файле .m.Хотя во многих примерах кода используется метод ленивого объявления.
Objective-C рассматривает функции как «сообщения», и поэтому вы можете отправить «сообщение» любому объекту — даже тому, в интерфейсе которого явно не указано, что он может принять.В результате в Obj-C нет таких вещей, как частные члены.
Это может быть очень мощно, но является источником путаницы для начинающих программистов Obj-C, особенно тех, кто работает на C++, Java или C#.Вот основные практические правила:
- Вы должны определить все общедоступные методы в своем @interface, чтобы потребители знали, какие сообщения вы собираетесь обрабатывать.
- Вам следует определить методы @private в вашем @interface, чтобы избежать сообщений компилятора и избежать необходимости упорядочивать методы в вашей @implementation.
- Вам следует использовать протоколы при реализации определенного соглашения о методах вашего класса.
Во многом это зависит от личных предпочтений, однако это помогает избежать надоедливых предупреждений компилятора и обеспечивает порядок в коде.и легко понять.