2012-05-17 17 views
11

Cuando declarar una propiedad, que puede poner varios atributos en la declaración, lo que tendrá un significado especial para el compilador:¿Puedo especificar atributos personalizados en miembros en Objective-C?

@property (nonatomic, retain) NSNumber *consumption; 

Aquí, nonatomic y retain son atributos. ¿Es posible agregar un atributo personalizado y poder verificar la existencia de este atributo en tiempo de ejecución? Por ejemplo:

@property (nonatomic, retain, test) NSNumber* consumption; 

Básicamente estoy usando desde hace un constructo que puede reemplazar el uso de atributos como los conozco desde C#/NET - sugerencias para alternativas también son bienvenidos..

+1

http://stackoverflow.com/questions/4919021/custom-property-attributes-in-objective-c – rishi

+0

@rishi, gracias, pero no estoy muy satisfecho con la respuesta a esa pregunta, ya que mi situación específica no no me permite crear otro tipo de devolución. Estoy buscando una respuesta sobre si es posible o no, y si es así, entonces cómo. – driis

+0

No es, desafortunadamente, sin modificar el compilador. –

Respuesta

4

No se pueden agregar atributos a @property() sin modificar el compilador.

Tenga en cuenta que, en general, arrancar incluso los atributos existentes de @property declaraciones en tiempo de ejecución se desaconseja completamente. El tiempo de ejecución ofrece una API a través de la cual puede hacerlo, pero no es para uso general y probablemente cambie en el futuro.

+0

Acabo de implementar un método que recorre todas las propiedades de una clase y crea automáticamente una asignación RestKit. ¿Por qué se desalienta el arranque de propiedades? – Nick

+0

@Nick Es frágil. Alguien podría agregar arbitrariamente una propiedad por categoría o en una superclase. O alguien podría crear un par de métodos setter/getter sin una declaración de propiedad. O uno puede declarar una propiedad que no está destinada a participar en su mapeo de RestKit. Más problemas para los implementadores del framework que las aplicaciones finales, pero es probable que encuentre que tener un método de consulta tipo "+ (NSArray *) attributesParticipatingInRestMapping" explícito reducirá los dolores de cabeza de mantenimiento con el tiempo. Exigir que el desarrollador agregue manualmente ese conjunto no es terriblemente oneroso y se auto documenta. – bbum

0

Siempre puede agregar un NSDictionary de nombres de propiedad a un NSArray de atributos. Esto se puede almacenar en una clase base o una clase separada que esté asociada con el objeto original a través de las API objc_setAssociatedObjects y objc_getAssociatedObjects.

Consulte here para obtener información sobre estas API. No es exactamente lo que estás buscando, ya que necesitarás cambiar el compilador, pero es una forma de agregar metadatos a cualquier objeto.

0

agregar atributos personalizados a la propiedad no es común, pero es deseable, creo. esta característica podría usarse para personalizar el recorrido de las propiedades de una clase. Deseé esta característica cuando manejo SQL: si tenemos atributos como: EXCLUDE_FROM_SELECT, INCLUDE_BY_INSERT, EXCLUDE_FROM_UPDATE ... entonces sería muy agradable.

En realidad, no estoy seguro de si hay una manera de habilitarlo para la directiva @property. sin embargo, podemos hacer algo similar:

si mira el archivo objc/runtime.h podría encontrar una función: class_replaceProperty, que no está documentada en el sitio web oficial. una función similar llamada class_addProperty está documentada y podría ayudarlo a comprender el argumento de la anterior. En realidad, creo que @property hace uso de estas funciones para realizar la configuración de la propiedad (pero no puedo probar que lo haga).

es posible que tenga las siguientes funciones:

void class_copyPropertyList(...); 
void property_copyAttributeList(...); 
void class_getProperty(...); 

mediante el uso de estas funciones, se podría hacer algo lo @property realmente hace.

lo que hice para el problema anterior de SQL es definir 3 funciones para registrar atributos personalizados:

void prepareClass(...); 
void registerAttributes(...); 
void endRegister(...); 

y entonces podríamos hacer el registro en la función de la clase de +initialize Tagart.

Sin embargo, hacer uso del código (compare con la simple @interface + @property declaration) puede no ser la mejor solución, ya que es posible que deseemos ver la configuración de la propiedad directamente de la declaración.Y en realidad podríamos hacerlo mejor mediante el uso de macros: __attribute__((constructor)) y

la @end @interface realidad le permiten hacer esto:

@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();}; 

, por lo tanto, se podría definir macros para manejar este hardcode:

#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) 

PD: la codificación anterior no es la codificación exacta, solo un ejemplo. Y no estoy seguro si la última solución macro funciona espero que esto pueda ayudar.

Cuestiones relacionadas