Почему переменные экземпляра определены в файле заголовка в Objective-C

Я могу понять определение функций в @interface файла заголовка, но почему переменные экземпляра? Должны ли переменные экземпляра быть закрытыми, доступными только через сообщения?

6 ответов

Причина в том, что он может вычислять смещения переменных для подклассов.

@interface Bird : NSObject {
 int wingspan;
}
@end
@interface ******* : Bird {
 NSPoint nestLocation;
 ******* *mate;
}
@end

Не зная структуры класса "Птица", класс "Пингвин" не может рассчитать смещение своих полей с начала структуры. Структура пингвинов выглядит примерно так:

struct ******* {
 int refcount; // from NSObject
 int wingspan; // from Bird
 NSPoint nestLocation; // from *******
 ******* *mate; // from *******
}

Это имеет побочный эффект: если вы изменяете размер класса в библиотеке, вы разбиваете все подклассы в приложениях, которые ссылаются на эту библиотеку. Новые свойства обходят эту проблему.


Я думаю, что это техническая проблема. Если я правильно понимаю, класс Objective-C - это просто причудливая структура C. И для структуры, которую нужно использовать, ее размер должен быть известен. (Как, как бы sizeof() работал иначе)


Хотя они объявлены в файле заголовка, вся переменная экземпляра в Objective-C имеет доступ по умолчанию @protected. Это означает, что переменная доступна в классе, который объявляет его и любой класс, наследующий от этого класса.

Вот документация Apple по определению класса Objective-C: Определение классов

Обратите внимание на раздел под названием "Объем переменных экземпляра".


Если кто-то столкнется с этим вопросом - с XCode 4.2 с компилятором LLVM вы можете объявить переменные экземпляра в @implementation, используя следующую скобку:

@interface SomeClass : NSObject
@end
@implementation SomeClass {
 NSString ********************;
}
- (void)moreMethods {}
@end

Переменные экземпляра обычно не должны быть частью объявленных публичным интерфейсом классов - они подробности реализации.

Однако УКАЗАТЬ вы определяете свои переменные экземпляра в фигурных скобках, иначе вы будете определять глобальную переменную, которая не имеет отношения к экземпляру объекта:

@implementation SomeClass
 NSString *whoopsGlobalVariable_;
- (void)moreMethods {}
@end


Из раздела документации Apple по определению классов Objective-C Роль интерфейса:

Хотя переменные экземпляра наиболее естественно рассматриваются как вопрос реализации класса, а не его интерфейса, они должны, тем не менее, быть объявлены в файле интерфейса. Это связано с тем, что компилятор должен знать структуру объекта, где он используется, а не только там, где он определен.


Обратите внимание, что в рамках нового "Современного времени выполнения" Objective C 2.0 (доступного в приложениях iPhone и 64-разрядных приложениях Mac OS X 10.5) вам не нужно указывать ivars, вы можете указать свойства, а затем использовать @synthesize для сгенерируйте ivars.

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

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

licensed under cc by-sa 3.0 with attribution.