2012-02-12 14 views
16

¿Hay alguna manera de recorrer todas las propiedades de un objeto y obtener su "nombre" y "valor"?Objetivo C - Looping a través de todas las propiedades en una clase?

Estoy tratando de escribir una categoría para serializar objetos a una cadena, en función de su nombre de propiedad y valores. Estoy tratando de evitar escribir métodos de codificación para cada clase, y en su lugar escribir uno genérico.

¿Esto es posible?

+3

Una idea admirable, pero por ese camino yace la locura. Va a reinventar la rueda (Core Data ya proporciona una excelente persistencia basada en modelos) y el sistema de propiedades * * no está diseñado para ser la base de cualquier tipo de persistencia automática. El resultado final será terriblemente frágil y será un verdadero dolor escribirlo en primer lugar, dados los caprichos de los tipos de datos C. – bbum

+0

A pesar de mi voto a favor en la respuesta de "propiedades, por favor" a continuación ... ESTO es cuando necesita ir a aprender los datos principales. En serio, valdrá la pena. No es para principiantes, sino para IMO, una vez que empiezas a hacer cosas como hackear el tiempo de ejecución objc, es hora de leer esos extraños documentos y darte la vuelta haciéndolo de la manera correcta. :) – buildsucceeded

+0

@buildsucceeded Sé cómo usar datos básicos. Es una gran solución cuando se trata de un proyecto de tamaño mediano/grande que requiere datos relacionales. Pero cuando se trata de un proyecto realmente pequeño donde todo lo que necesito para serializar un solo objeto para mantener el estado de la aplicación, es una sobreestimación el uso de datos centrales. Además, utilicé esta solución para otros fines, como Object-To-Dictionary-Serialization y un DI Framework – aryaxt

Respuesta

21

Puede usar este código para enumerar todas las propiedades declaradas en una clase y todos los atributos de las propiedades. Supongo que estás más interesado en analizar el atributo tipo. Se detallan 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

Tenga en cuenta que no hay definiciones razonables de los diversos nombres expuestos por un motivo; es un detalle de implementación que puede cambiar en el futuro. – bbum

+0

@ bbum De acuerdo, pero la información expuesta es lo suficientemente útil para, por ejemplo, generar métodos de acceso para propiedades dinámicas en tiempo de ejecución. – Costique

+0

@Costique ¿qué pasa con la liberación de cadenas .name, .value en cada atributo en atributos array? ¿Quién tiene la propiedad sobre ellos, el tiempo de ejecución o el desarrollador? – Andy

1

Tal vez class_copyPropertyList() hará lo que está buscando, pero tenga en cuenta que solo devuelve las propiedades declaradas.

No todas las propiedades están declaradas - NSDictionary y NSMutableDictionary son ejemplos de clases donde puede establecer propiedades que no están declaradas en la clase.

Más en el docs.

2

Yo uso de los siguientes Gama de NSObject decir, por ejemplo, NSLog(@"%@", [someObject propertiesPlease]);, lo que resulta en una entrada de registro como ...

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

NSObject + Additions.h

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

NSObject + Additions.m

@implementation NSObject (Additions) 
- (NSDictionary *)propertiesPlease { 
NSMutableDictionary *props = [NSMutableDictionary dictionary]; 
unsigned int outCount, i; 
objc_property_t *properties = class_copyPropertyList([self class], &outCount); 
for (i = 0; i < outCount; i++) { 
    objc_property_t property = properties[i]; 
    NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property)]; 
    id propertyValue = [self valueForKey:(NSString *)propertyName]; 
    if (propertyValue) [props setObject:propertyValue forKey:propertyName]; 
} 
    free(properties); 
    return props; 
} 
@end 
+1

oh querido dios esto se siente tan sucio ... – buildsucceeded

+1

initWithCString está en desuso, [[NSString alloc] initWithBytes: property_getName (propiedad) length: strlen (property_getName (property)) encoding: NSUTF8StringEncoding] funcionará en su lugar. –

+0

¿Debería liberarse el valor de retorno de 'property_getName'? –

0

Aún no tengo privilegios de comentario, pero para agregar a la respuesta de @ Costique, hay un atributo adicional Tipo valor "V" que es el nombre del IVar al que se puede enlazar una propiedad (a través de sintetizar) Esto puede ser descubierta fácilmente con este

@interface Redacted: NSObject

@property (atómico, de sólo lectura) 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] Atributo 0: nombre: T, valor: i

2013-07-08 13 : 47: 16.601 Redactado [5162: 303] Atributo 1: nombre: R, valor:

2013-07-08 13:47:16.602 Redacted [5162: 303] Atributo 2: nombre: V, valor: fooBar

Cuestiones relacionadas