Как сделать реальную частную переменную экземпляра? - PullRequest
51 голосов
/ 11 августа 2009

Я хочу создать переменную экземпляра, к которой нет доступа извне. Возможно ли что-то подобное в target-c? Я помню, у Apple есть личные переменные и тому подобное, но если люди знают о них, они могут их использовать. Apple называет это «частным API», но, очевидно, другие могут получить доступ к этому материалу, если узнают, что там есть.

До сих пор я считал, что что-то подобное создает частную переменную экземпляра:

@interface MyClass : NSObject {
    CGFloat weight;
}

Нет @property, нет @synthesize, только объявление выше.

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

В чем тут подвох?

Ответы [ 7 ]

60 голосов
/ 11 августа 2009

Вы можете использовать ключевое слово @private внутри {}, чтобы сделать все последующие объявления переменных закрытыми. Видимость по умолчанию - @protected (что похоже на protected в Java), и это в целом работает хорошо. Вам нужно было бы специально объявить переменную как @public, чтобы она была напрямую доступна вне класса.

Эта документация Apple содержит дополнительную информацию о переменной области видимости и видимости.

Существует также разница между "частным API" и частными переменными. В Objective-C вы не можете сделать методы частными - любой может вызвать любой метод. Есть несколько способов создания «секретных» методов, но это несколько выходит за рамки этого вопроса. Вот несколько связанных с этим вопросов SO:

Что касается ведущей _ перед переменными, помните, что Apple также резервирует этот префикс для "частных" методов. Лучший способ гарантировать, что вы избежите проблем, - это использовать обычные соглашения об именах для ваших собственных переменных и методов. Однако, если вы не создадите подклассы в Cocoa (кроме NSObject), вы можете быть достаточно уверены, что у вас не возникнет проблем.

31 голосов
/ 09 июня 2011

С новым LLVM-компилятором, доступным в XCode 4 и более поздних версиях, вы можете объявить @private переменные в категориях по умолчанию в файле вашей реализации (.m):

@interface ClassName()
{
@private
// private variables here
}
@end

@implementation ClassName
// you can use private variables here
@end

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

9 голосов
/ 19 августа 2012

Вы можете определить частные методы, просто имея их только в @implementation, а не в интерфейсе @.

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

См. Следующий пример.

@interface EXClass : NSObject
{
uint8_t publicInteger;
float publicFloat;
}

-(void)publicMethod;
@end

@implementation EXClass
{
uint8_t privateInteger;
float privatefloat;
}

-(BOOL)privateMethod {
return FALSE;
}

Помните, что методы target-C отправляются в виде сообщений во время выполнения (однако, вместо привязки времени компиляции C ++), так что RespondsToSelector: все равно вернет true, а executeSelector: все равно вызовет метод. Ивари были бы полностью частными.

Если бы вы создавали библиотеку, теоретически никто бы не знал ни о каких методах, которые вы не объявили в заголовочных файлах.

3 голосов
/ 11 августа 2009

Все iVars в Objective-C защищены по умолчанию. Если вы не напишите методы доступа, то другие классы не смогут видеть переменные.

Два исключения являются категориями и подклассами.

2 голосов
/ 05 марта 2013

Я видел следующее использование в примере приложения (PaintGL) от Apple

В .m файле

@interface MyClass (private)
  - (void) privateMethod();
  @property(...) myProperty;
@end

Отказ от ответственности: в примере приложения есть только объявления методов, я видел объявление частного свойства в этой теме SO

2 голосов
/ 12 августа 2009

Документы Apple для именования переменных экземпляра явно не предупреждают об использовании подчеркивания в имени переменных экземпляра, как это делают документы закрытого метода.

Переменные экземпляра именования и типы данных

Я также помню разговор Уилла Шипли с несколькими другими разработчиками OS X, касающимися подчеркивания. Из-за способа работы компилятора Obj-C, если Apple добавит новую переменную экземпляра в класс в своих инфраструктурах, это приведет к перекомпиляции всех приложений, использующих эти платформы. Что касается уже существующих переменных экземпляра, вы должны получить предупреждение, когда вы наступаете на одну.

1 голос
/ 06 сентября 2013

Вы можете , а не сделать настоящую частную переменную экземпляра. Objective-C - это динамический язык, и поэтому есть доступ к любой переменной (даже @private).

Мой лучший подход:

Используйте его в блоке реализации вашего файла .m. Тогда не виден и блок KVC, так что KVC не будет работать

@implementation ClassName {
    // default to @protected
    // but the subclasses can't see ivars created in the implementation block
    float number;
}

+ (BOOL)accessInstanceVariablesDirectly {
    return NO; // no KVC
}

@end
...