Подтвердить что ты не робот

Как объявить переменные экземпляра и методы, невидимые или используемые вне экземпляра класса?

Я просмотрел кучу сообщений по этому вопросу. Возможно, я не перебежал через "один", и кто-то укажет мне в этом направлении. Вопрос прост и, вероятно, имеет простой ответ.

Если у вас есть два ivars, скажем, "public_ivar" и "private_ivar", где/как вы должны их объявлять, чтобы общедоступность была общедоступной, а частная не подвергалась никому, кто смотрит на заголовочный файл

Тот же вопрос в случае "public_method" и "private_method".

Мне нравятся чистые файлы заголовков (на других языках), которые выставляют только методы и ivars, которые я хочу видеть другим. Вы должны быть в состоянии опубликовать свой файл заголовка и не столкнуться с опасностью того, что кто-то получит доступ к тому, чего они не должны. Как вы это делаете в objective-C.

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

4b9b3361

Ответ 1

Вы можете объявлять переменные экземпляра или объявленные свойства в расширении класса. Поскольку расширение класса объявляется в файле реализации (т.е. Не в файле заголовка), они не будут видны кому-либо, проверяющему файл заголовка. Например, в файле заголовка:

@interface SomeClass : NSObject
@end

и в файле реализации:

@interface SomeClass ()
@property (nonatomic, assign) int privateInt;
@end

@implementation SomeClass

@synthesize privateInt;
…
@end

или

@interface SomeClass () {
    int privateInt;
}
@end

@implementation SomeClass
…
@end

Обратите внимание, что theres ничего не препятствует доступу к переменным экземпляра private/class extension (или методам доступа для свойств, объявленных в расширении класса) во время выполнения. Я написал довольно подробное сообщение об этом в качестве ответа на другой вопрос о переполнении стека: Создает ли private @property переменную экземпляра @private?

Изменить: Переменные экземпляра в расширениях классов были представлены на сессии 144 WWDC 2010.

Изменить: "Используя компилятор Clang/LLVM 2.0, вы также можете объявлять свойства и переменные экземпляра в расширении класса."

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1

Ответ 2

Используйте расширения класса для добавления к классу в вашем файле реализации. Расширение класса в основном представляет собой неназванную категорию с несколькими бонусами: свойства, объявленные в ней, могут быть синтезированы, и все, что объявлено в ней, должно быть в основной реализации, поэтому компилятор может проверить, чтобы убедиться, что вы не пропустили реализацию. Вы должны поставить расширение класса до своей реализации. Вы не можете добавлять переменные экземпляра непосредственно в расширение класса, но вы можете добавлять свойства. Когда вы синтезируете аксессоры для свойств, у которых нет соответствующих переменных экземпляра, новая среда выполнения (os x 10.5 и более поздние версии и все версии iOS, я полагаю) автоматически создадут переменные экземпляра. Это означает, что вы не можете создавать свои собственные аксессоры, если только вы не введете переменную экземпляра в свой заголовок. Частные методы могут быть добавлены к расширению класса без ограничений, но, как заметила Аномия, технически возможно использовать их, если вы знаете, что они называются, и с помощью класса-дампа ничего не безопасно.

Пример использования расширения класса:

@interface MyClass ()
@property (retain) id privateIvar;
@property (readwrite) id readonlyProperty; // bonus! class extensions can be used to make a property that is publicly readonly and privately readwrite
- (void)privateMethod;
@end
@implementation MyClass
@synthesize privateIvar; // the runtime will create the actual ivar, and we just access it through the property
- (void)privateMethod {
    ...
}
...

Другим способом создания "переменных экземпляра" без помещения их в заголовок или с использованием свойства является использование ассоциативных ссылок, которые добавляют данные в объект во время выполнения. Они не являются технически такими же, как переменные экземпляра, и синтаксис для них более сложный. Поскольку они также требуют новой среды выполнения, есть только две причины, по которой вы действительно захотите их использовать: вы хотите добавить переменную экземпляра в категорию (вне сферы действия этого вопроса), или вам нужно, чтобы она действительно была конфиденциальной. Ассоциативная ссылка не создает каких-либо методов или не добавляет определения класса в скомпилированный код, поэтому, если вы не создаете для них обертки, их невозможно узнать без запроса объекта после добавления данных. См. Нижнюю часть страницы, которую я связал для полного примера использования.

Ответ 3

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