2012-02-12 12 views
16

C'è un modo per scorrere tutte le proprietà in un oggetto e ottenere il loro "nome" e "valore".Objective- C: looping attraverso tutte le proprietà in una classe?

Sto provando a scrivere una categoria per serializzare gli oggetti su una stringa, in base al loro nome e ai loro valori di proprietà. Sto cercando di evitare di scrivere metodi di codifica per ogni classe, e invece di scriverne uno generico.

È possibile?

+3

Un'idea ammirevole, ma su questa strada giace la follia. Potrai reinventare la ruota (i dati principali forniscono già un'eccellente persistenza basata sul modello) e il sistema di proprietà * non * è progettato per essere la base per qualsiasi tipo di persistenza automatizzata. Il risultato finale sarà terribilmente fragile e sarà un dolore completo da scrivere in primo luogo, dati i capricci dei tipi di dati C. – bbum

+0

Nonostante la mia upvote sulla "proprietà per favore" rispondi di seguito ... QUESTO è quando devi andare ad apprendere i Core Data. Seriamente, ne varrà la pena. Non è per i principianti ma IMO una volta che inizi a fare cose come hackerare il runtime objc è il momento di leggere quegli strani documenti e farti girare la testa nel modo giusto. :) – buildsucceeded

+0

@buildsucceeded So come utilizzare i dati principali. È un'ottima soluzione quando si tratta di un progetto di medie/grandi dimensioni che richiede dati relazionali. Ma quando si tratta di un progetto molto piccolo in cui tutto ciò che serve per serializzare un singolo oggetto per mantenere lo stato dell'applicazione, è un over-kill per usare i core-data. Inoltre, ho usato questa soluzione per altri scopi come Object-To-Dictionary-Serialization e DI Framework – aryaxt

risposta

21

È possibile utilizzare questo codice per enumerare tutte le proprietà dichiarate in una classe e tutti gli attributi delle proprietà. Immagino che tu sia più interessato a analizzare l'attributo type. Sono dettagliate here.

unsigned int numOfProperties; 
objc_property_t *properties = class_copyPropertyList([self class], &numOfProperties); 
for (unsigned int pi = 0; pi < numOfProperties; pi++) { 
    // Examine the property attributes 
    unsigned int numOfAttributes; 
    objc_property_attribute_t *propertyAttributes = property_copyAttributeList(properties[pi], &numOfAttributes); 
    for (unsigned int ai = 0; ai < numOfAttributes; ai++) { 
     switch (propertyAttributes[ai].name[0]) { 
      case 'T': // type 
       break; 
      case 'R': // readonly 
       break; 
      case 'C': // copy 
       break; 
      case '&': // retain 
       break; 
      case 'N': // nonatomic 
       break; 
      case 'G': // custom getter 
       break; 
      case 'S': // custom setter 
       break; 
      case 'D': // dynamic 
       break; 
      default: 
       break; 
     } 
    } 
    free(propertyAttributes); 
} 
free(properties); 
+1

Si noti che nessuna definizione sensata dei vari nomi è esposta per un motivo; è un dettaglio di implementazione che potrebbe cambiare in futuro. – bbum

+0

@bbum Concordato, ma le informazioni esposte sono abbastanza utili per, ad esempio, generare metodi di accesso per le proprietà dinamiche in fase di runtime. – Costique

+0

@Costique: cosa significa rilasciare stringhe .name, .value in ogni attributo dell'array di attributi? Chi ha la proprietà su di loro, runtime o sviluppatore? – Andy

1

Forse class_copyPropertyList() farà ciò che si desidera, ma si noti che restituisce solo le proprietà dichiarate.

Non tutte le proprietà sono dichiarate - NSDictionary e NSMutableDictionary sono esempi di classi in cui è possibile impostare proprietà non dichiarate nella classe.

Ulteriori informazioni su docs.

2

Io uso il seguente Categoria sul NSObject a dire, ad esempio, NSLog(@"%@", [someObject propertiesPlease]);, con conseguente una voce di registro come ...

someObject: { 
    color = "NSCalibratedRGBColorSpace 0 0 1 1"; 
    crayon = Blueberry; 
} 

NSObject + Additions.h

@interface NSObject (Additions) 
- (NSDictionary *)propertiesPlease; 
@end 

NSObject + Additions.m

+1

oh caro dio questo sembra così sporco ... – buildsucceeded

+1

initWithCString è deprecato, [[NSString alloc] initWithBytes: proprietà_getName (proprietà) lunghezza: strlen (proprietà_getName (proprietà)) codifica: NSUTF8StringEncoding] funzionerà invece. –

+0

Il valore restituito di 'property_getName' deve essere liberato? –

0

Non ho ancora i privilegi di commento, ma per aggiungere alla risposta di @ Costique, c'è un attributo aggiuntivo Valore di tipo "V" che è il nome di IVar a cui una proprietà può essere associata (via sintetizza). Questo può essere facilmente scoperto con questo

@interface Redacted: NSObject

@property (atomico, di sola lettura) int foo;

@end


@implementation Redacted

@synthesize foo = foobar;

@end

// for all properties 
unsigned propertyCount = 0; 
objc_property_t *properties = class_copyPropertyList([object class], &propertyCount); 
for (int prop = 0; prop < propertyCount; prop++) 
{ 
    // for all property attributes 
    unsigned int attributeCount = 0; 
    objc_property_attribute_t* attributes = property_copyAttributeList(property, &attributeCount); 
    for (unsigned int attr = 0; attr < attributeCount; attr++) 
    { 
     NSLog(@"Attribute %d: name: %s, value: %s", attr, attributes[attr].name, attributes[attr].value); 
    } 
} 

2013-07-08 13: 47: 16.600 Redacted5162: 303] Abilità 0: nome: T, valore: i

2013-07-08 13 : 47: 16.601 Redacted [5162: 303] Attributo 1: nome: R, valore:

2013-07-08 13:47:16.602 Redacted [5162: 303] Attributo 2: nome: V, valore: fooBar

Problemi correlati