Вопрос по declaration, api-design, objective-c, definition – Когда я определяю методы target-c?

34

Я изучаю Objective-C и имею опыт работы с C / C ++.

In object-oriented C++, you always need to declare your method before you define (implement) it, even if it is declared in the parent class.

In procedural-style C, IIRC, you can get away with just defining a function so long as it is only called from something else in the same compilational unit (ie. the same file) that came later on in the file (well, provided you don't declare it elsewhere with "extern").

Now, in Objective-C, it appears that you only need to declare selectors in the header file if they are going to be used by something external, and that you can make up selectors in your .m file just fine, and call them within the .m file. Also, it appears that delegate methods or inherited methods are never (re)defined.

Я на правильном пути? Когда вам нужно определить селектор в Objective-C?

Ваш Ответ

3   ответа
78

Для методов Objective-C общей практикой является размещение методов, которые вы хотите показать в@interface раздел заголовочного файла, поэтому другой код может включать только .h и знать, как взаимодействовать с вашим кодом. Основанная на заказе «ленивая декларация» работает так же, как функции в C & # x2014; Вы неhave to объявите прототип метода, если только у вас нет зависимости, которую нельзя решить с помощью упорядочения, но вы можете добавить прототипы метода внутри@implementation если нужно.

Так что да, вы на правильном пути. Не повторяйте прототип метода для унаследованных методов & # x2014; компилятор находит его в заголовочном файле родителя. Методы делегата могут быть определены как прототипы в категории (привязаны к классу) и реализованы по желанию, но делегату не нужно предоставлять прототип метода, поскольку он уже определен. (Все еще может, если захочет для ясности и т. Д.)

Since you're just learning Objective-C, the rest of this answer is much more detail than you asked for. You have been warned. ;-)


Когда вы статически вводите переменную (например,MyClass* вместоid) компилятор предупредит вас, когда вы попытаетесь вызвать метод, который класс не объявляет о том, что он реализует, независимо от того, делает он это или нет. Если вы динамически вводите переменную, компилятор не остановит вас от вызова того, что вам нравится, и вы получите ошибки времени выполнения только в том случае, если вы вызовете что-то, чего не существует. Что касается языка, вы можете вызывать любой метод, который класс реализует без ошибок во время выполнения & # x2014; нет способа ограничить, кто может вызвать метод.

Лично я думаю, что это на самом деле хорошая вещь. Мы настолько привыкли к инкапсуляции и защите нашего кода от другого кода, что иногда мы относимся к вызывающей стороне как к обманщику, а не как к доверенному сотруднику или клиенту. Я нахожу, что довольно приятно кодировать с помощью мышления "ты делаешь свою работу, а я делаю свою" где каждый уважает границы и заботится о своем. Вы можете сказать, что «отношение» Objective-C является одним из доверия сообщества, а не строгого принуждения. Например, я рад помочь любому, кто придет ко мне на стол, но будет очень раздражен, если кто-то напутает с моими вещами или переместит вещи без вопросов. Хорошо продуманный код не обязательно должен быть параноидальным или социопатическим, он просто должен хорошо работать вместе. :-)

Тем не менее, существует много подходов для структурирования ваших интерфейсов, в зависимости от уровня детализации, который вы хотите / нуждаетесь в представлении интерфейсов пользователям. Любые методы, которые вы объявляете в общедоступном заголовке, по сути являются честной игрой для всех. Сокрытие объявлений методов похоже на блокировку вашего автомобиля или дома & # x2014; это, вероятно, не будет держать всех в стороне, но (1) оно "держит честных людей честными" не соблазняя их чем-то, с чем они не должны связываться, и (2) любым, ктоdoes Конечно, они будут знать, что они не должны этого делать, и не могут жаловаться на негативные последствия.

Ниже приведены некоторые соглашения, которые я использую для именования файлов, а также описание каждого файла & # x2014; начиная с файла .m внизу, каждый файл содержит файл над ним. (Использование строгой цепочки включений предотвратит такие вещи, как предупреждения о дублировании символов.) Некоторые из этих уровней применимы только к более крупным повторно используемым компонентам, таким как платформы Какао. Адаптируйте их в соответствии со своими потребностями и используйте любые имена, которые вам подходят.

  • MyClass.h — Public API (Application Programming Interface)
  • MyClass_Private.h — Company-internal SPI (System Programming Interface)
  • MyClass_Internal.h — Project-internal IPI (Internal Programming Interface)
  • MyClass.m — Implementation, generally of all API/SPI/IPI declarations
  • MyClass_Foo.m — Additional implementation, such as for categories

API для всех, и он публично поддерживается (обычно вFoo.framework/Headers). SPI предоставляет дополнительные функциональные возможности для внутренних клиентов вашего кода, но с пониманием, что поддержка может быть ограничена, и интерфейс может быть изменен (обычно вFoo.framework/PrivateHeaders). IPI состоит из специфических для реализации деталей, которые никогда не должны использоваться вне самого проекта, и эти заголовки вообще не включены в структуру. Любой, кто решает использовать вызовы SPI и IPI, делает это на свой страх и риск, и обычно в ущерб, когда изменения нарушают их код. :-)

@Quinn Большое спасибо за ваше драгоценное время .. действительно один из прекрасных ответов на SO :)
Я надеюсь, что я не упускаю суть, но я часто задавался вопросом, возможно ли скрыть переменные-члены, используя эту структуру многоуровневых API, или все еще нужно объявить в MyClass.h?
+1 Отличный ответ! :)
+1. Спасибо за то, что нам не нужны стальные пластины, чтобы сотрудники не могли связываться с нашими кубами, и нам не нужно принудительное использование языка, чтобы они не мешали внутренним структурам данных. Если нам нужно, нам нужны лучшие сотрудники. Предупреждения компилятора важны (наряду с -Werror), так же, как маленькие ярлыки на еде в холодильнике, говорящие «это мое, не ешьте это». ObjC - это язык для взрослых. Вы следуете правилам, даже если ваша мама (компилятор) вас не принуждает. И поэтому вам не нужно находить хитрости в компиляторе, как это часто бывает в других языках.
3

Objective-C рассматривает функции как «сообщения» и как таковой, вы можете отправить «сообщение» к любому объекту, даже к тому, который явно не указывает в своем интерфейсе, что он может принять. В результате в Obj-C нет таких вещей, как частные члены.

Это может быть очень мощным, но может привести к путанице для новых программистов на Obj-C, особенно для тех, кто работает на C ++, Java или C #. Вот основные практические правила:

  • You should define all public methods in your @interface so that consumers know what messages you expect to handle.
  • You should define @private methods in your @interface to avoid compiler messages and avoid having to order the methods in your @implementation.
  • You should use protocols when implementing a particular convention of methods for your class.

Во многом это личное предпочтение, однако оно помогает избежать раздражающих предупреждений компилятора и сохраняет ваш код организованным. и легко понять.

Пояснение: & quot; @ private & quot; Ключевое слово может использоваться только для объявлений переменных, но не методов. Методы, предназначенные быть закрытыми, могут быть объявлены в дополнительном файле заголовка, который включает в себя открытый заголовок и включен в реализацию (вместо открытого заголовка).
6

Объявление методов в заголовочном файле только остановит предупреждения компилятора. Objective-C - это динамический язык, поэтому вы можете вызывать метод (отправлять сообщение) объекту независимо от того, объявлен ли этот метод извне.

Кроме того, если вы определили метод в файле .m над любым кодом, который его вызывает (отложенное объявление), он не будет генерировать никаких предупреждений. Однако применимо то же самое, вы можете отправить сообщение объекту без его объявления.

Конечно - это означает, что в Objective-C нет частных методов. Любой метод, который реализует класс, может быть вызван.

Личное предпочтение. Если это публичный метод (то есть один используемый снаружи). объявите это в .h и определите в .m. Если вы хотите ограничить его видимость или хотя бы указать, что это частный метод, используйтекатегории / расширения класса в .m файле. Хотя во многих примерах кода используется метод ленивого объявления.

Похожие вопросы