2012-05-17 8 views
11

Quando mi dichiaro una proprietà, posso mettere i vari attributi nella dichiarazione, che avrà un significato speciale per il compilatore:Posso specificare attributi personalizzati sui membri in Objective-C?

@property (nonatomic, retain) NSNumber *consumption; 

Qui, nonatomic e retain sono attributi. È possibile aggiungere un attributo personalizzato ed essere in grado di verificare l'esistenza di questo attributo in fase di runtime? Per esempio:

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

sto usando per fondamentalmente un costrutto che può sostituire l'uso di attributi come li conosco da C#/NET - suggerimenti in modo alternativi sono anche benvenuti..

+1

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

+0

@rishi, grazie, ma non sono molto soddisfatto della risposta a questa domanda, poiché la mia situazione specifica non mi consente di creare un altro tipo di reso. Sto cercando una risposta sul fatto che sia possibile o meno - e se sì, allora come. – driis

+0

Non è, sfortunatamente, senza modificare il compilatore. –

risposta

4

Non è possibile aggiungere attributi a @property() senza modificare il compilatore.

Si noti che, in generale, l'estirpazione anche degli attributi esistenti delle dichiarazioni @property in fase di esecuzione è completamente scoraggiata. Il runtime offre un'API tramite la quale è possibile farlo, ma non è destinato all'uso generico e probabilmente cambierà in futuro.

+0

Ho appena implementato un metodo che scorre tutte le proprietà di una classe e crea automaticamente una mappatura RestKit. Perché l'estirpazione attraverso le proprietà è scoraggiata? – Nick

+0

@Nick È fragile. Qualcuno potrebbe arbitrariamente aggiungere una proprietà tramite categoria o in una superclasse. Oppure qualcuno potrebbe creare una coppia di metodi setter/getter senza una dichiarazione di proprietà. Oppure si potrebbe dichiarare una proprietà che non è destinata a partecipare alla mappatura RestKit. Altri problemi per gli implementatori di framework rispetto alle applicazioni finali, ma è probabile che avere un esplicito metodo di query di tipo "+ (NSArray *) attributesParticipatingInRestMapping" ridurrà il mal di testa della manutenzione nel tempo. Richiedere allo sviluppatore di aggiungere manualmente quel set non è terribilmente oneroso e si auto-documenta. – bbum

0

È sempre possibile aggiungere un NSDictionary di nomi di proprietà a un NSArray di attributi. Questo può essere memorizzato in una classe base o in una classe separata associata all'oggetto originale tramite objc_setAssociatedObjects e objc_getAssociatedObjects API.

Vedere here per informazioni su queste API. Non è esattamente quello che stai cercando dato che dovrai modificare il compilatore, ma è un modo per aggiungere metadati a qualsiasi oggetto.

0

l'aggiunta di attributi personalizzati alla proprietà non è comune ma auspicabile. questa funzione potrebbe essere utilizzata per personalizzare l'attraversamento delle proprietà di una classe. Ho desiderato questa funzionalità quando gestisco SQL: se abbiamo attributi come: EXCLUDE_FROM_SELECT, INCLUDE_BY_INSERT, EXCLUDE_FROM_UPDATE ... allora sarebbe molto bello.

In realtà, non sono sicuro che ci sia un modo per abilitarlo per la direttiva @property. tuttavia, potremmo fare qualcosa di simile:

se si osserva objc/runtime.h è possibile trovare una funzione: class_replaceProperty, che non è documentata nel sito Web ufficiale. una funzione simile denominata class_addProperty è documentata e potrebbe aiutarti a capire l'argomento del precedente. In realtà, penso che @property utilizzi queste funzioni per eseguire le impostazioni delle proprietà (ma non riesco a dimostrarlo).

potrebbe essere necessario anche le seguenti funzioni:

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

utilizzando queste funzioni, si potrebbe fare qualcosa quello @property realmente fa.

quello che ho fatto per il precedente problema di SQL è quello di definire 3 funzioni per registrare attributi personalizzati:

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

E poi abbiamo potuto fare il registro in funzione +initialize della classe tagart.

Tuttavia, l'utilizzo del codice (confrontare con la semplice @interface + @property declaration) potrebbe non essere la soluzione migliore, perché potremmo voler vedere le impostazioni delle proprietà direttamente dalla dichiarazione.E in realtà siamo riusciti a fare meglio utilizzando __attribute__((constructor)) e le macro:

il @end @interface in realtà permette lo fare questo:

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

conseguenza, è possibile definire le macro per gestire questa 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) 

PS: la codifica di cui sopra non è la codifica esatta, è solo un esempio. E non sono sicuro che l'ultima macro soluzione funzioni spero che questo possa aiutare.

Problemi correlati