varias superponer studio modificar lineas graficos graficas ejes objective-c introspection objective-c-runtime declared-property

objective-c - studio - superponer graficas en r



Obtener el nombre de la propiedad como una cadena (9)

Necesito una forma de pasar una propiedad y obtener el nombre asignado. ¿Alguna sugerencia?

@property (nonatomic, retain) MyObject *crazyObject; NSString *str = SOME_WAY_TO_GET_PROPERTY_NAME(crazyObject); // Above method should return @"crazyObject"


Al modificar la solución, funciona cuando su objeto ya está asignado, de lo contrario, devuelve nil: -

NSString * NSStringFromProperty(NSObject* property, NSObject* class) { unsigned int propertyCount = 0; objc_property_t * properties = class_copyPropertyList([class class], &propertyCount); NSString *name = nil; for (unsigned int i = 0; i < propertyCount; ++i) { name = [NSString stringWithUTF8String:property_getName(properties[i])]; NSObject *object = [class valueForKey:name]; if (object != nil && object == property) { break; } else { name = nil; } } free(properties); return name; }


Aquí hay una función que devuelve el nombre de un ivar, así que básicamente no solo devuelve las propiedades sino cualquier ivar de la clase. No he encontrado una forma de obtener la propiedad directamente, así que usé el truco de ivar.

#import <objc/objc.h> /// ----- - (NSString *)nameOfIvar:(id)ivarPtr { NSString *name = nil; uint32_t ivarCount; Ivar *ivars = class_copyIvarList([self class], &ivarCount); if(ivars) { for(uint32_t i=0; i<ivarCount; i++) { Ivar ivar = ivars[i]; id pointer = object_getIvar(self, ivar); if(pointer == ivarPtr) { name = [NSString stringWithUTF8String:ivar_getName(ivar)]; break; } } free(ivars); } return name; }



Después de buscar y depurar, encuentro una solución para mí ...

Se agregó #import <objc/runtime.h>

Los métodos object_getIvar (id obj, Ivar ivar) envían acceso incorrecto y bloqueos de aplicaciones. Modifico un código y funcionó de maravilla:

+(NSString*)stringWithProperty:(id)property withClass:(id)controller { NSString *name = nil; uint32_t ivarCount; Ivar *ivars = class_copyIvarList([controller class], &ivarCount); if(ivars) { for(uint32_t i=0; i<ivarCount; i++) { Ivar ivar = ivars[i]; name = [NSString stringWithUTF8String:ivar_getName(ivar)]; if ([controller valueForKey:name] == property) { break; } } free(ivars); } return name; }


Es tan simple como esto ... expandir sobre lo que Chuck ya mencionó:

#ifndef STR_PROP #define STR_PROP( prop ) NSStringFromSelector(@selector(prop)) #endif

Luego lo usa así:

NSString *strProp = STR_PROP(myProperty);


Puede consultar mi enfoque en Gist para obtener la cadena de una propiedad con autocompletado y verificación en tiempo de compilación.

Cómo utilizar:

Obtener el nombre de la propiedad para una clase :

@interface AnyClass : NSObject @property (strong) NSData *data; @end // == My approach == // C string for a class PropertyNameForClass(AnyClass, data); // ==> "data" // NSString for a class PropertyStringForClass(AnyClass, data); // ==> @"data" // Bad approach (no autocompletion; no compile-time check): NSString *propertyName = @"data";

Obtener el nombre de la propiedad para un protocolo :

@protocol AnyProtocol @property (strong) NSDate *date; @end // C string for a protocol PropertyNameForProtocol(AnyProtocol, date); // ==> "date" // NSString for a protocol PropertyStringForProtocol(AnyProtocol, date); // ==> @"date"


Puedes intentar esto:

unsigned int propertyCount = 0; objc_property_t * properties = class_copyPropertyList([self class], &propertyCount); NSMutableArray * propertyNames = [NSMutableArray array]; for (unsigned int i = 0; i < propertyCount; ++i) { objc_property_t property = properties[i]; const char * name = property_getName(property); [propertyNames addObject:[NSString stringWithUTF8String:name]]; } free(properties); NSLog(@"Names: %@", propertyNames);


Puedes usar

NSString *str = NSStringFromSelector(@selector(crazyObject));

Lo bueno de este enfoque es que:

  1. Xcode autocompletará la palabra crazyObject por usted.
  2. Cuando más tarde cambie el nombre de la propiedad de crazyObject a myCrazyObject , Xcode agregará una advertencia que diga "unrecognized selector!" - bastante bueno para la depuración.

Utilizo este método tan a menudo, que incluso creé una función, que permite escribir menos letras:

NSString * __nonnull sfs(SEL __nonnull theSelector) { if (!theSelector) { abort(); } return NSStringFromSelector(theSelector); }

Ahora su solución final puede verse así:

NSString *str = sfs(@selector(crazyObject));


Fondo

Tenga en cuenta que las propiedades son realmente justas, para citar a Apple , "una abreviatura sintáctica para declarar los métodos de acceso de una clase". De hecho, por sí mismo, la declaración @property ni siquiera funciona. Su instrucción @synthesize traduce @property en el equivalente de dos métodos:

- (void)setCrazyObject:(MyObject *)something; - (MyObject *)crazyObject;

El que se usa depende del contexto que rodea a su self.crazyObject. ( @synthesize también crea una variable de instancia coincidente si no lo hiciste tú mismo). La consecuencia de todo esto es que no puedes traducir desde y hacia una propiedad con un solo método.

Solución propuesta

Puede usar lo que Apple ya proporciona:

NSString *foo = NSStringFromSelector(@selector(myClassProperty));

O haz algo personalizado:

Dado que self.crazyObject realmente se traduce en [self crazyObject] o [self setCrazyObject:foo] cuando se ejecuta su código, probablemente necesite dos métodos, como:

- (NSString *)setterStringForProperty:(SEL)prop; - (NSString *)getterStringForProperty:(SEL)prop;

Es posible que desee al menos 2 métodos complementarios, como:

- (SEL)setterForPropertyName:(NSString *)propString; - (SEL)getterForPropertyName:(NSString *)propString;

Dentro de estos métodos, puede usar las funciones Foundation NSStringFromSelector y NSSelectorFromString para convertir entre SEL y NSString. Utilice las manipulaciones de cadena que desee para convertir hacia adelante y hacia atrás entre su cadena setter (setCrazyObject) y su nombre de propiedad (crazyObject).

Es difícil proporcionar una solución completa sin conocer el caso de uso exacto, pero es de esperar que esto proporcione algunas pistas más para cualquiera que intente lograr algo similar. Incluso podría haber algunas cosas útiles hechas posible combinando este enfoque con la respuesta de Oscar.