С каких это пор можно объявить Objective-C 2.0 свойства в категории?
Я всегда думал, что нельзя объявлять свойство объекта в категории.
Пока мой партнер не сделал это в нашем коде приложения, и он, похоже, работал.
Я продолжал говорить о том, что вы пытаетесь объяснить ему, что нет, Objective-C можно использовать только для добавления методов, а не свойств. Я нашел такие вопросы, как:
Но затем я нашел эту ссылку на сайте Apple, который содержит следующее о объявлении @property:
Объявление свойства начинается с ключевое слово @property. @property может появляются в любом месте метода список деклараций, найденный в @interface класса. @property может также появляются в декларации протокола или категории. (выделено мной)
Я знаю, что это не работает:
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
Но это компилируется:
@interface MyClass ()
@property NSInteger foobar;
- (void) someCategorizedMethod;
@end
Мой вопрос: (a) что лучше всего здесь? и (b) это что-то новое для Objective-C 2.0, и вместо использования "реального" iVar он просто использует ассоциативную память за кулисами, чтобы сделать эту работу?
Ответы
Ответ 1
Вы всегда можете объявить @property
в категории. То, что вы не могли сделать - и все еще не можете - объявить хранилище для свойства в категории, ни как переменную экземпляра, ни через `@synthesize.
Однако....
@interface MyClass ()
не является категорией. Это расширение класса и имеет значительно более конкретную роль, чем категория.
А именно, расширение класса можно использовать для расширения класса @interface, и это включает в себя @properties, которые могут быть @synthesized (включая синтез хранилища в современной среде исполнения).
Foo.h:
@interface Foo
@end
Foo.m:
@interface Foo()
@property int x;
@end
@implementation Foo
@synthesize x; // synthesizes methods & storage
@end
он просто использует ассоциативное хранилище за кадром, чтобы сделать эту работу?
Нет - это реальная переменная экземпляра. Современная среда выполнения устраняет проблему хрупкого базового класса.
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
Вышеупомянутое не работает (как и ожидалось), потому что foobar
является, фактически, глобальной переменной.
Если вы измените его на:
@interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
@end
Затем он будет работать с последней версией компилятора llvm (с правильными флагами, как указано в комментарии @Joshua).
Ответ 2
Вообще говоря, свойства ничем не отличаются от других методов. До тех пор, пока используемый ivar доступен в обычном классе, нет никаких проблем. Это просто синтаксический сахар.
Все начинает усложняться, если также автоматически создается ivar, как это возможно в некоторых конфигурациях.
Главное, что объявление ivar не зависит от свойства.
Ответ 3
Ассоциативное хранилище - это решение.
Посмотрите на post.