Как объявить переменные экземпляра и методы, не видимые или не используемые вне экземпляра класса? - PullRequest
13 голосов
/ 29 апреля 2011

Я просмотрел кучу постов на эту тему.Может быть, я не столкнулся с «одним», и кто-то укажет мне в этом направлении.Вопрос прост и, вероятно, имеет простой ответ.

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

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

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

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

Ответы [ 3 ]

17 голосов
/ 29 апреля 2011

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

@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

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

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

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

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

4 голосов
/ 29 апреля 2011

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

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

@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 {
    ...
}
...

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

2 голосов
/ 29 апреля 2011

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

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