Как отдельный экземпляр переменной?


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

до сих пор я считал, что что-то вроде этого создает частный экземпляр переменной:

@interface MyClass : NSObject {
    CGFloat weight;
}

нет свойство@, нет @синтезировать, просто объявление выше.

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

в чем тут фишка?

7 51

7 ответов:

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

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

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

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

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

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

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

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

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

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

рассмотрим следующий пример.

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

-(void)publicMethod;
@end

@implementation EXClass
{
uint8_t privateInteger;
float privatefloat;
}

-(BOOL)privateMethod {
return FALSE;
}

помните, что методы objective-C отправляются как сообщения во время выполнения (а не привязка времени компиляции C++), поэтому respondsToSelector: все равно вернет true и performSelector: все равно вызовет метод. Ивары будут полностью приватны.

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

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

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

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

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

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

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

In .файл м

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

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

вы можете не сделать реальную переменную частного экземпляра. 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