Objective-C: как предотвратить утечку абстракции

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

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

Интересно, есть ли эквивалентный выбор в Objective-C, или я действительно должен объявить каждый ivar в .h для моего класса.

Ари.


person iter    schedule 30.03.2010    source источник
comment
+1, и для примечания Subjective-C.   -  person Ben Zotto    schedule 30.03.2010


Ответы (4)


Ари,

Хорошая ссылка на то, как выполнять «невидимые» объявления переменных экземпляра, может можно найти здесь с уважением к Мэтту Галлахеру.

Надеюсь, это поможет, Фрэнк.

person Frank C.    schedule 30.03.2010
comment
Правильно. Часть, которая на самом деле отвечает на мой вопрос, заключается в том, что я могу поместить часть @interface в свой файл .m. Спасибо за указатель. - person iter; 31.03.2010

Переменные экземпляра традиционно необходимы для определения размера класса. Прямой доступ к иварам всегда был плохой практикой, и это не главное. В современной среде выполнения это менее необходимо, но в любом случае это не утечка абстракции, если только клиенты не полагаются на переменные класса, что должно быть невозможно, поскольку вы объявляете их как @protected или @private, верно?

person Chuck    schedule 30.03.2010
comment
Спасибо, что указали на первоначальное положительное намерение явного перечисления иваров. Я использую действительно динамические языки (Python, Lisp) так долго, что забыл, что некоторые языки хотят знать размеры во время компиляции. Во многих смыслах изучение Objective-C похоже на путешествие по закоулкам памяти. Или в шахте: я вижу все слои отложений, которые накапливаются в языке за время его существования. - person iter; 30.03.2010
comment
@iter: в Objective-C больше нет необходимости. Современная среда выполнения работает так же, как Python, где переменные экземпляра могут быть назначены волей-неволей без объявления в заголовке, но язык по-прежнему сохраняет синтаксис своего прошлого. - person Chuck; 30.03.2010
comment
Я думаю, что мог столкнуться с этим на днях, когда я начал сталкиваться с прерывистыми ошибками objc_msgSend_fixup. Я не уверен на 100%, но проблема исчезла, когда я удалил object_setClass, который использовал для приведения объекта к пользовательскому классу с добавленными свойствами. - person Elise van Looij; 30.03.2010
comment
@Elise van Looij: Это потому, что object_setClass не актерский состав, и это совсем не правильный способ сделать это. - person Chuck; 30.03.2010
comment
Обратите внимание, что я специально сказал, что вы можете присваивать объекту произвольные переменные, а не то, что вы можете безопасно превратить объект одного класса в объект какого-то другого произвольного класса. Это часть, которая не будет работать. - person Chuck; 30.03.2010

Чтобы ограничить доступ, вы можете использовать ключевые слова @private или @protected:

@interface Foo : NSObject {
    @private
    int barPrivate;

    @protected
    int barProtected;

    @public
    int barPublic;
}
@end

РЕДАКТИРОВАНИЕ: Поцарапать все, оказывается, мне действительно нужно немного поспать.

person Can Berk Güder    schedule 30.03.2010
comment
Правильно, вы не можете добавлять переменные экземпляра с категорией. - person codewarrior; 30.03.2010
comment
Создайте более одного экземпляра с разными значениями для bar, и вы увидите — bar — это глобальная переменная. - person Chuck; 30.03.2010
comment
@Chuck: см. мое последнее редактирование. 4:33 утра, CBG завершает работу. Примечание для себя: просмотрите весь код, который вы написали за последние 2 часа, когда проснетесь. - person Can Berk Güder; 30.03.2010

Ивары по умолчанию @protected (хотя @private и @protected не гарантируют, что другие классы не смогут получить к ним доступ — вы всегда можете получить доступ к иварам с getValue:forKey:). Вы никогда не должны напрямую обращаться к ivars из других классов напрямую в любом случае - "выбор" заключается в том, следует ли выставлять ivars как свойства (вам просто нужно полагаться на все классы, следующие соглашению, чтобы не обращаться к ivars напрямую).

В новой среде выполнения target-c вам вообще не нужно объявлять ивары, так как они могут быть синтезированы во время выполнения, но, к сожалению, это не работает с симулятором iPhone, поэтому на данный момент лучше просто объявить все ivars в файле .h.

person shosti    schedule 30.03.2010
comment
Я меньше беспокоюсь о том, чтобы код клиента не сделал что-то странное с моим кодом, и больше беспокоюсь о том, чтобы сообщить программисту клиента больше о моей реализации, чем он хочет знать. Когда я читаю файл .h, я хочу узнать внешнюю форму библиотеки, которую использую. Если я хочу знать его внутреннюю работу, я читаю .c или .m, в зависимости от обстоятельств. Мне нравится держать эти два отдельных и отдельных. - person iter; 30.03.2010
comment
Я согласен - раздражает, что ivars находятся в файле .h, но, как упоминалось выше, я думаю, что это на благо компилятора. - person shosti; 30.03.2010