В Objective-C, в чем разница между определением чего-либо (скажем, свойства) в заголовочном файле, в отличие от файла .m? - PullRequest
4 голосов
/ 28 января 2012

В Objective-C, в чем разница между определением чего-либо (скажем, свойства или метода) в файле заголовка, в отличие от файла .m?Я слышал, что это связано с тем, чтобы сделать его публичным или частным, но я не уверен в деталях.Если это так, это то же самое, что публичные и приватные методы в Java?

Я опытный в Java, так что любой способ, которым вы можете связать Objective-C с этим, будет полезен.Класс (если это правильный термин) называется «CalculatorBrain», в чем разница между следующими (обратите внимание на NSMutableArray * operandStack:

В файле .m:

 @interface CalculatorBrain()
 @property (nonatomic, strong) NSMutableArray *operandStack;
 @end

против, в файле .h:

 @interface CalculatorBrain : NSObject
 @property (nonatomic, strong) NSMutableArray *operandStack;
 @end

Какая разница, где я определяю NSMutableArray *?

Ответы [ 5 ]

3 голосов
/ 28 января 2012

Хорошо, после вашего разъяснения я постараюсь объяснить, что там происходит.

Допустим, у вас есть это в файле заголовка (.h):

@interface Foobar {
}
@property (readonly) int numberOfPies;
@end

Это определение общедоступного интерфейса class . В то время как я сказал «публичный» там, я хочу четко дать понять, что Objective-C не имеет той же концепции видимости, что и Java или C ++ (он использует ее для переменных экземпляра, но это самое дальнее, что я в курсе). Я также выделил «класс», потому что есть важное различие, подходящее. Еще одна вещь, на которую я хочу обратить внимание, это то, что класс публично объявляет numberOfPies равным readonly, поскольку это также будет важно.

Теперь давайте рассмотрим файл реализации (.m) для этого класса:

@interface Foobar ()
- (void) doSomething;
@property (readwrite) numberOfPies;
@end

@implementation Foobar
@synthesize numberOfPies;

- (void) doSomething {
  NSLog(@"Doing something");
}

@end

Посмотрите на @interface Foobar () - начинается расширение класса . Это не объявление класса. Их также иногда называют частными категориями, анонимными категориями или продолжениями классов (согласно zneak в комментарии ниже), но важно знать, что они в основном являются своего рода категорией ( связан с документацией Apple по категориям). Они по существу определяют дополнительные методы и свойства и могут применяться к любому классу вообще. Они используются здесь для предоставления того, что составляет частный интерфейс для класса (отсюда и «частная категория»).

Двигаясь дальше, теперь мы сравним свойство numberOfPies между классом и категорией. Если вы еще не заметили разницу, вот она: класс представляет ее как readonly, категория расширяет ее и делает ее readwrite внутри реализации. При синтезировании свойства Obj-C будет включать в себя как получатель, так и установщик, если это произойдет. Здесь важно то, что независимо от того, является ли ваша собственность readonly или readwrite, ваша собственность не может измениться. Он не может иметь атрибут assign в классе и copy в категории. Это в основном позволяет вам определить удобный частный установщик для свойств.

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

После этого у вас есть стандартная реализация. Это включает в себя реализации методов в вашей анонимной категории.

1 голос
/ 28 января 2012

Система классов Objective C отличается от системы Java - она ​​разделяет объявление и определение. Вы определяете свои свойства в файле .h

@property(...) int X;

и затем определите его метод получения / установки (или синтез) в файле .m. Теперь вам не нужно объявлять их в .h. Потребители классов по-прежнему смогут получить к нему доступ, но компилятор выдаст вам предупреждение о том, что «класс может не поддерживать ...». Такова динамическая природа ObjC.

С другой стороны, если вы объявляете свойство, но не определяете / не синтезируете его, компилятор будет жаловаться на неполный ваш класс.

Есть одно исключение из этого правила. Если свойство не объявлено, но существует метод getter / setter / @ synthesize, компилятор позволит вам использовать его внутри реализации класса с того момента, как оно было определено в файле. Это не то же самое, что частный доступ Java, поскольку свойство все еще доступно (за счет предупреждения) извне класса. Это самая близкая вещь для частного доступа, которую может предложить ObjC.

0 голосов
/ 28 января 2012

В самом «чистом» смысле главное отличие состоит в том, что файл .h предназначен для включения в другие файлы, поэтому объявленные там члены класса должны быть видимы извне; файл .m не предназначен для включения где-либо, и поэтому все, что объявлено там, вероятно, не будет видно где-либо еще.

В отличие от Java и других популярных языков, глобальный символ (будь то класс, структура, функция или переменная) не может быть доступен, если он не был объявлен до его использования. Вот почему скрытие объявления в файле .m затрудняет доступ к символу извне.

0 голосов
/ 28 января 2012

В C вы обычно компилируете .c файлы (или, для Objective-C, .m файлы, они аналогичны) один за другим в большие двоичные объекты собственного кода.(Этими объектами являются .o файлы.) При компиляции данного файла .c компилятор не просматривает другие файлы .c, чтобы увидеть, какие функции в них определены.Что вы можете сделать, это дать компилятору объявлений (в основном имена и подписи) функций, которые будут доступны позже, когда будет связывать .

A .h файлэто в основном список этих объявлений.Это манифест всех функций (методов и т. Д.) В файле .c, которые можно вызывать в других файлах .c.Поэтому обычно он должен включать только то, что необходимо в этих других файлах.(«Открытые» функции.)

Второй этап построения программы на C - это связывание , когда файлы .o объединены вместе и ссылки на функции между ними связаны.

В Java у вас есть .class файлы;файл класса содержит как читаемые компилятором сигнатуры методов класса, так и байт-код их реализаций.Аналогия с C заключается в том, что компилятор Java автоматически извлекает заголовки, которые будут помещены в файл .h, и включает их в начале файла .o.

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

(вышепо общему признанию это грубое упрощение способа работы с Си, и его можно настроить совершенно по-разному. Я полагаю, что соглашение «один файл С на один заголовочный файл» довольно обычное для ObjC.)

0 голосов
/ 28 января 2012

Вы только объявляете свойство в @interface.Вы определяете его в @implementation.

, объявление публикует клиентам или компилятору, что свойство существует, его тип и атрибуты.

определение - фактическая реализация.без определения реализация не будет существовать.то есть вы можете ожидать исключения «не отвечает селектору» без определения.

Это так же, как вы видите в C:

// only a declaration
int fun(void);

// a definition
int fun(void) {
   ...
}

, но вы не всегда получаетеошибка компоновщика с ObjC.

Какая разница, где я определяю NSMutableArray *?

Люди часто скрывают некоторые из их объявления в расширении класса (как в вашем примере), но оно действительно отличается от видимости (например, public, protected, private).Методы могут по-прежнему вызываться извне, или члены могут быть доступны через среду выполнения (и несколько других случаев).Это попытка инкапсуляции, но это не такая надежная гарантия, как в других языках (Java или C ++).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...