2012-02-13 17 views
9

Voglio creare una classe base Objective-C che esegua un'operazione su tutte le proprietà (di tipi diversi) in fase di esecuzione. Poiché i nomi e i tipi di proprietà non saranno sempre noti, come posso fare qualcosa di simile?Ciclo attraverso tutte le proprietà dell'oggetto in fase di esecuzione

@implementation SomeBaseClass 

- (NSString *)checkAllProperties 
{ 
    for (property in properties) { 
     // Perform a check on the property 
    } 
} 

EDIT: Questo sarebbe particolarmente utile in un costume - (NSString *)description: override.

risposta

21

Per espandere sulla risposta MVDS' (iniziato a scrivere questo prima ho visto la sua), ecco un esempio di programma poco che utilizza il runtime API Objective-C per scorrere e stampare le informazioni su ogni proprietà in una classe:

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

@interface TestClass : NSObject 

@property (nonatomic, retain) NSString *firstName; 
@property (nonatomic, retain) NSString *lastName; 
@property (nonatomic) NSInteger *age; 

@end 

@implementation TestClass 

@synthesize firstName; 
@synthesize lastName; 
@synthesize age; 

@end 

int main(int argc, char *argv[]) { 
    @autoreleasepool { 
     unsigned int numberOfProperties = 0; 
     objc_property_t *propertyArray = class_copyPropertyList([TestClass class], &numberOfProperties); 

     for (NSUInteger i = 0; i < numberOfProperties; i++) 
     { 
      objc_property_t property = propertyArray[i]; 
      NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)]; 
      NSString *attributesString = [[NSString alloc] initWithUTF8String:property_getAttributes(property)]; 
      NSLog(@"Property %@ attributes: %@", name, attributesString); 
     } 
     free(propertyArray); 
    } 
} 

uscita: attributi

età proprietà: T^q, Vage
proprietà lastName attributi: T @ "NSString", &, N, VlastName
proprietà firstName attributi: T @ "NSString", &, N, VfirstName

Si noti che questo programma deve essere compilato con ARC acceso.

+0

Una buona domanda di followup sarebbe come restituire i valori di ciascuno in modo dinamico ... Sto pensando di creare dinamicamente una accessor, ma sintatticamente, sto ancora cercando di capirlo. –

+1

Ci sono un paio di modi per farlo, ma il più semplice sarebbe usare KVC: 'id value = [self valueForKey: @" propertyName "]'. Diventa un po 'più complicato in cui si hanno tipi di ritorno primitivi (int, float, ecc.) E object (NSString, ecc.), Ma la premessa di base funzionerà. –

+0

questo codice fa trapelare come l'inferno – mvds

14

Usa

objc_property_t * class_copyPropertyList(Class cls, unsigned int *outCount) 

e leggere https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html su come fare esattamente questo.

del codice per farti andare:

#import <objc/runtime.h> 

unsigned int count=0; 
objc_property_t *props = class_copyPropertyList([self class],&count); 
for (int i=0;i<count;i++) 
{ 
    const char *name = property_getName(props[i]); 
    NSLog(@"property %d: %s",i,name); 
} 
+1

Stellare. Risorsa perfetta per la follia del runtime più vicina al metallo. –

+0

Grazie mille, funziona bene, come faccio a copiare le proprietà di un oggetto in un altro in fase di runtime? –

+1

@PavanSaberjack usando 'valueForKey:' e 'setValue: forKey:', dove si deve prendere atto che 'char * name' non può essere usato come oggetto (cioè come' NSString') senza alcuna forma di conversione. – mvds

Problemi correlati