Objective-C: простой вопрос об объявлениях файлов заголовков

Здесь новичок, разрабатывающий для iPhone, с чрезвычайно простым вопросом: в чем причина объявления метода в файле заголовка, а затем его заполнения в файле реализации? Это нужно делать всегда?

Кроме того, я знаю, что нужно объявлять переменные в @interface файла заголовка, но почему они только иногда повторяются с тегом @property? Это для переменных, из которых другие классы могут захотеть читать или писать (поэтому они автоматически создают методы получения и установки)?

С уважением.


person achiral    schedule 31.08.2011    source источник


Ответы (5)


Объявление метода в файле .h называется предварительным объявлением. Если вы объявляете заголовок метода в файле .h, компилятор будет знать имя метода, параметры и тип возвращаемого значения до фактического связывания. Вы можете написать тело метода только в файле .m. Но этот метод может использоваться только методами, объявленными после него в этом файле. Но если вы объявите метод в заголовке, то это не будет проблемой. Потому что тогда сигнатура метода будет известна всем во время первого прохода компилятора и будет связана на втором проходе.

Теги @property и @synthesize используются для создания автоматических методов получения и установки (или Accessors и Mutators в терминологии Objective-C), но это еще не все. В iOS вам придется вручную управлять памятью (в iOS5 это нужно изменить, как обещал Apple). В теге @property вы можете указать, как будет вести себя память во время назначения.

iOS отслеживает управление памятью объекта, поддерживая счетчик удержания. Когда вы выделяете объект, его счетчик сохранения становится равным 1. Затем вы можете вручную увеличить счетчик сохранения с помощью метода сохранения (например, [myObj retain]) или уменьшить счетчик сохранения с помощью метода освобождения (например, [myObj release]). Когда счетчик сохранения упадет до 0 iOS удалите этот объект из памяти. С помощью тега @property вы можете определить, как будет управляться счетчик удержания во время назначения. Например, два наиболее часто используемых параметра в теге @property:

@property (nonatomic, retain)
@property (nonatomic, assign)

В первом случае во время присвоения счетчик сохранения объекта будет автоматически увеличен на 1 (например, self.myObj = anotherClass.anotherObjOfSameClass;), а в последнем случае счетчик сохранения не будет увеличиваться.

person rushafi    schedule 31.08.2011
comment
Конечно, все правильно, но, возможно, новичку не нужно сильно беспокоиться о подсчете ссылок, потому что компилятор сделает это за вас, начиная со следующего выпуска, в соответствии с общедоступными операторами и изменениями в LLVM. Понимание полезно, как и любое понимание технологии, лежащей в основе технологии, которую вы используете, но я думаю, что это перестанет быть фундаментальным. Соответственно, он в значительной степени заменяет «сохранить» и «назначать» на «сильные» и «слабые», чтобы указать, хотите ли вы сильную связь (например, сохранение) или слабую (что-то вроде назначения, но с самообнулением). Так что это цель, а не реализация. - person Tommy; 31.08.2011
comment
В Objective-C 3.0 вообще нецелесообразно объявлять частный метод. Порядок тоже уже не актуален. - person Binarian; 16.12.2013

Смысл файла заголовка на любом языке C состоит в том, чтобы отделить реализацию от доступных методов. То есть вы определяете шаблон класса в файле заголовка, чтобы кто-то, использующий ваш код, мог просто сказать: «О, хорошо, я хочу использовать этот и этот метод, и теперь я знаю, как создать экземпляр объекта этого класса». Все дело в абстракции. :-)

person Vinay    schedule 31.08.2011
comment
И я не уверен, но похоже, что тег @property предназначен для генерации геттеров и сеттеров. Я никогда не занимался разработкой для iOS. - person Vinay; 31.08.2011
comment
@synthesize необязательно генерирует реализации геттеров / сеттеров. @ property объявляет их, @ synth не требуется. - person bbum; 31.08.2011
comment
^ О'кей, в этом гораздо больше смысла. - person Vinay; 31.08.2011

Я думаю, это просто сделать два файла, один для публичного API (.h) и вашу логику и реализацию в (.m), чтобы скрыть от других людей. Также тег свойства помогает создавать геттеры и сеттеры для вашей переменной.

вы используете @property в файле заголовка, а затем @synthesize его в реализации, что позволит вам получить доступ к геттерам и сеттерам.

Читайте дальше,

http://developer.apple.com/library/mac/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html#//apple_ref/doc/uid/TP40007594

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

#import <UIKit/UIKit.h>

@interface FileSystemDemoViewController : UIViewController {

    UITextView *actorListBox;
    NSArray *dataToShow;
}

@property (nonatomic, retain) IBOutlet UITextView *actorListBox;
@property (nonatomic, retain) NSArray *dataToShow;

-(IBAction) covertToAscending:(id)sender;
-(IBAction) covertToDescending:(id)sender;

@end

@implementation
...Your implementation here...
@end

Прежде всего, код находится в файле .m, Реализация.

снова НЕ РЕКОМЕНДУЕТСЯ

Удачного кодирования

person TeaCupApp    schedule 31.08.2011

Зачем разделять файлы .h и .m?

Исторически сложилось так, что в C, когда вы включали файл .h, это было почти буквально эквивалентно вставке файла в файл, который его включал. Фактически, все ваши объявления повторялись в каждом файле, который их использовал. Это нормально, в C вы можете повторять объявления сколько угодно, пока они не меняются. Однако повторение определений приведет к появлению нескольких копий функции и общей поломке. Следовательно, вы не можете включать весь код модуля, только его объявления.

Я думаю, что Objective-C на самом деле умнее, и вы могли бы, если хотите, вообще не иметь файлов .m и поместить весь код в файлы .h. Вы также можете определить класс только в файле .m и не иметь файла .h, но вы не можете создать такой проект целиком, поскольку ничто не сможет получить доступ к чему-либо еще.

Однако по-прежнему рекомендуется отделять объявления от определений. Это как иметь меню в ресторане вместо того, чтобы возвращаться на кухню и смотреть, что готовится. Файл .h - это краткое описание того, как другие модули могут использовать содержимое модуля.

Почему некоторые переменные экземпляра имеют свойства, а некоторые - нет?

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

Еще одна вещь, которую вы получаете со свойствами, - это автоматическое управление памятью. Если вы используете атрибут сохранения, когда вы присваиваете значение свойству, счетчик сохранения значения увеличивается, а счетчик сохранения предыдущего значения (если он есть) уменьшается. Это очень удобно и позволяет избежать наворотов. Даже если другие классы не имеют доступа к переменной экземпляра, это полезно. Если вы не используете свойства, вы должны убедиться, что выполняете соответствующие инструкции по сохранению и освобождению в методах экземпляра, чтобы избежать утечки памяти. Есть и другие варианты автоматического поведения свойств, например блокировка или копирование.

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

person morningstar    schedule 31.08.2011

Как уже отмечалось, исходная причина для файлов .h и .m заключается в том, что компиляторы C обрабатывают каждый исходный файл изолированно, а затем соединяют точки между ними только тогда, когда они приходят для связывания. Следовательно, должен быть какой-то механизм, с помощью которого объявления могут распространяться - чтобы каждый файл по отдельности можно было проверять на ошибки и предупреждения компилятора - но определения оставались в одном месте - чтобы компоновщик мог гарантировать, что общие ресурсы окажутся в общем месте.

Что касается современной среды выполнения, различие между файлами .h и .m лучше рассматривать как различие между интерфейсом и реализацией. Интерфейс - это то, что вы публикуете для всеобщего обозрения. Реализация предназначена только для ознакомления с этим классом. Ваш единственный контракт с внешним миром определяется интерфейсом.

Objective-C, как и большинство объектно-ориентированных языков, использует концепцию геттеров и сеттеров для свойств объекта. У объектов нет доступа к переменной экземпляра других объектов, вместо этого они спрашивают «что это за значение?» или «пожалуйста, установите значение этого». До Objective-C 2.0 вам приходилось писать геттеры и сеттеры самостоятельно, что приводило к появлению большого количества повторяющегося шаблонного кода. Первоначальной целью @property было объявление геттеров или сеттеров в интерфейсе. @synthesize используется для генерации реализации по умолчанию для чего-то, объявленного как @property.

Что касается новой среды выполнения, нет необходимости объявлять переменные экземпляра в интерфейсе, вы можете полностью сохранить их в рамках реализации. Так, например:

SomeClass.h:

@interface SomeClass: NSObject

- (void)doSomeTask;

@end

SomeClass.m:

// declare a category with some unexposed properties
@interface SomeClass ()
@property (nonatomic, assign) NSMutableArray *arrayForMe;
@end

@implementation SomeClass

@synthesize arrayForMe; // you can now use the property self.arrayForMe,
                        // even though you didn't declare a backing
                        // instance variable

- (void)doSomePrecursorTask
{
    // ...
}

- (void)doSomeTask
{
    // as a fact of implementation, I need to do something else
    // first. Because it's an implementation specific, I don't
    // want to put it in the declared interface

    [self doSomePrecursorTask];
    // ...
}

@end

Новая среда выполнения доступна на iOS, Lion и 64-битном Snow Leopard. В соответствии с передовой практикой, вероятно, имеет смысл убрать переменные экземпляра из файлов заголовков. Просто поместите туда публичный интерфейс и думайте о них как о способе формализации и общения. Я ожидал, что переменные экземпляра в заголовке очень быстро будут выглядеть так же старомодно, как NSEnumerator.

person Tommy    schedule 31.08.2011
comment
Я искал конкретную причину, а именно: у объектов нет доступа к переменной экземпляра других объектов. Думаю, это наиболее полный ответ. - person Praveen S; 31.08.2011
comment
да. Вероятно, с оговоркой, что в старой среде выполнения при работе с подклассом компилятору необходимо было знать общий размер всех переменных экземпляра, используемых соответствующими суперклассами - следовательно, почему они находятся в заголовке. Ему не нужно знать это в новой среде выполнения, поэтому нет причин помещать их в заголовок. Вы все еще можете, но я бы посоветовал не делать этого на том основании, что это означает публикацию конкретной реализации. - person Tommy; 31.08.2011