2009-06-19 5 views
34

Я изучаю Objective-C и имею фон C/C++.Когда я определяю методы object-c?

  • В объектно-ориентированном C++, вы всегда должны объявить метод, прежде чем определить (реализовать), даже если он объявлен в родительском классе.

  • В процедуре C, IIRC вы можете избежать просто определения функции, если она вызывается только из чего-то другого в том же компиляционном блоке (то есть в том же файле), который появился позже в файл (ну, если вы не объявляете его в другом месте «extern»).

  • Теперь, в Objective-C, вам нужно только объявить селектора в файле заголовка, если они будут использоваться чем-то внешним, и что вы можете создавать селектор в своем .m-файле просто отлично , и вызовите их в файле .m. Кроме того, похоже, что методы делегата или унаследованные методы никогда (re) не определены.

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

ответ

78

Для методов 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, делает это на свой страх и риск и обычно в ущерб, когда изменения нарушают их код. :-)

+12

+1. Благодарим за то, что нам не нужны стальные пластины, чтобы сотрудники не путались с нашими кубами, и нам не нужно требовать языкового принуждения, чтобы они не вмешивались во внутренние структуры данных. Если нам это нужно, нам нужны лучшие коллеги. Предупреждения компилятора важны (наряду с -Werror), точно так же, как маленькие этикетки на еде в холодильнике, говорящие «это мое, не ешьте». ObjC - это язык для взрослых. Вы следуете правилам, даже когда ваша мама (компилятор) не заставляет вас. И поэтому вам не нужно находить трюки вокруг компилятора, как вы часто это делаете на других языках. –

+1

+1 Отличный ответ! :) –

+0

Надеюсь, я не пропущу точку, но часто задавался вопросом, можно ли скрыть переменные-члены с помощью этой структуры многоуровневых API или все еще нужно объявить в MyClass.h? – Akusete

6

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

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

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

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

3

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

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

  • Вы должны определить все общедоступные методы на вашем @interface, чтобы потребители знали, какие сообщения вы собираетесь обрабатывать.
  • Вы должны определить @private методы в @interface, чтобы избежать сообщений компилятора и не нужно заказывать методы в @implementation.
  • Вы должны использовать протоколы при реализации определенного соглашения методов для своего класса.

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

+1

Уточнение: ключевое слово «@private» может использоваться только для объявлений переменных, а не для методов. Методы, которые должны быть частными, могут быть объявлены в дополнительном файле заголовка, который включает в себя общий заголовок и включается в реализацию (вместо публичного заголовка). –

 Смежные вопросы

  • Нет связанных вопросов^_^