Могу ли я указать пользовательские атрибуты для членов в Objective-C?
Когда я объявляю свойство, я могу поместить в объявление различные атрибуты, которые будут иметь особое значение для компилятора:
@property (nonatomic, retain) NSNumber *consumption;
Здесь nonatomic
и retain
являются атрибутами. Можно ли добавить пользовательский атрибут и проверить возможность существования этого атрибута во время выполнения? Например:
@property (nonatomic, retain, test) NSNumber* consumption;
Я использую в основном конструкцию, которая может заменить использование атрибутов, поскольку я знаю их из С#/. NET, поэтому приветствуются альтернативные предложения.
Ответы
Ответ 1
Вы не можете добавлять атрибуты к @property()
без изменения компилятора.
Обратите внимание, что, вообще говоря, обрезание даже существующих атрибутов объявлений @property
во время выполнения довольно тщательно обескуражено. Среда выполнения предлагает API, через который вы можете это сделать, но он не предназначен для общего использования и, скорее всего, изменится в будущем.
Ответ 2
Вы всегда можете добавить NSDictionary имен свойств в NSArray атрибутов. Это может быть сохранено в базовом классе или отдельном классе, который связан с исходным объектом через API objc_setAssociatedObjects и objc_getAssociatedObjects.
См. здесь для получения информации об этих API. Это не совсем то, что вы ищете, поскольку вам нужно будет сменить компилятор, но это способ добавления метаданных к любому объекту.
Ответ 3
Добавление пользовательских атрибутов в свойство не является общим, но желательно, я думаю. эта функция может использоваться для пользовательского обхода свойств класса. Я хотел эту функцию, когда я обрабатываю SQL: если у нас есть такие атрибуты, как: EXCLUDE_FROM_SELECT
, INCLUDE_BY_INSERT
, EXCLUDE_FROM_UPDATE
..., тогда было бы очень приятно.
На самом деле, я не уверен, есть ли способ включить его для директивы @property. однако мы можем сделать что-то подобное:
если вы посмотрите на objc/runtime.h, вы можете найти функцию: class_replaceProperty
, которая не задокументирована на официальном веб-сайте. аналогичная функция, называемая class_addProperty
, документирована и может помочь вам понять аргумент предыдущего. На самом деле, я думаю, что @property использует эти функции для выполнения настроек свойств (но я не могу это доказать).
вам также могут потребоваться следующие функции:
void class_copyPropertyList(...);
void property_copyAttributeList(...);
void class_getProperty(...);
используя эти функции, вы можете сделать что-то, что на самом деле делает @property.
Что я сделал для предыдущей проблемы SQL, так это определить 3 функции для регистрации пользовательских атрибутов:
void prepareClass(...);
void registerAttributes(...);
void endRegister(...);
И тогда мы могли бы сделать регистр в функции +initialize
вашего класса tagart.
Однако использование кода (сравнение с простым объявлением @interface + @property) может быть не лучшим решением, потому что мы можем захотеть увидеть настройки свойств непосредственно из объявления. И на самом деле мы могли бы сделать это лучше, используя __attribute__((constructor))
и макросы:
@interface @end позволяет вам сделать это:
@interface MyVO : NSObject
__attribute__((constructor))
void prepareForMyVO(){ prepareClass(MyVO);}
@property (strong) id p1;
__attribute__((constructor))
static void registerAttrForP1(){ registerAttributes("p1", EXCLUDE_FROM_SELECT);}
@property (strong) id p2;
__attribute__((constructor))
static void registerAttrForP2(){ registerAttributes("p2", INCLUDE_BY_INSERT);}
@end
__attribute__((constructor))
static void endRegisterForMyOV(){ endRegister();};
поэтому вы можете определить свои макросы для обработки этого жесткого кода:
#define $p(clazz, zuper) class : zuper \
__attribute__((constructor)) static void prepareFor ## clazz(){ prepareClass(#MyVO);}
#define $r(p, attr) p; \
__attribute__((constructor)) static void registerAttrFor ## p(){ registerAttributes(#p, attr);}
#define $e(clazz) __attribute__((constructor)) static void endRegister ## clazz(){ endRegister();};
@interface $p(MyVO, NSObject)
@property (strong) id $r(p1, EXCLUDE_FROM_SELECT);
@property (strong) id $r(p1, INCLUDE_BY_INSERT);
@end $e(MyVO)
PS: приведенное выше кодирование не является точным кодированием, это просто пример. И я не уверен, работает ли последнее решение макросов
надеюсь, что это может помочь.