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