Почему переменные экземпляра определены в заголовочном файле в Objective-C - PullRequest
6 голосов
/ 09 июня 2009

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

Ответы [ 6 ]

8 голосов
/ 09 июня 2009

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

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

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

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

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

6 голосов
/ 09 июня 2009

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

6 голосов
/ 09 июня 2009

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

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

Обратите внимание на раздел под названием «Область действия переменных».

5 голосов
/ 05 ноября 2011

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


@interface SomeClass : NSObject
@end

@implementation SomeClass {
  NSString *myInstanceVariable_;
}

- (void)moreMethods {}
@end

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

Однако, MAKE SURE вы определяете переменные вашего экземпляра в фигурных скобках, иначе вы будете определять глобальную переменную, которая не имеет отношения к экземпляру объекта:


@implementation SomeClass
  NSString *whoopsGlobalVariable_;

- (void)moreMethods {}

@end
3 голосов
/ 09 июня 2009

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

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

2 голосов
/ 09 июня 2009

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

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

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

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