Pregunta

Tengo object_getInstanceVariable para trabajar como aquí sin embargo, parece funcionar solo para flotadores, bools e ints no dobles. Sospecho que estoy haciendo algo mal, pero he estado yendo en círculos con esto.

float myFloatValue;
float someFloat = 2.123f;
object_getInstanceVariable(self, "someFloat", (void*)&myFloatValue);

funciona y myFloatValue = 2.123

pero cuando lo intento

double myDoubleValue;
double someDouble = 2.123f;
object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);

Obtengo myDoubleValue = 0 . Si intento configurar myDoubleValue antes de la función, por ejemplo. double myDoubleValue = 1.2f , el valor no cambia cuando lo leo después de la llamada object_getInstanceVariable . Establecer myIntValue en algún otro valor antes de que la función getinstancevar anterior devuelva 2 como debería, es decir. ha sido cambiado.

luego lo intenté

Ivar tmpIvar = object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);

Si hago ivar_getName (tmpIvar) obtengo " someDouble " ;, pero myDoubuleValue = 0 todavía. Luego intento ivar_getTypeEncoding (tmpIvar) y obtengo " d " como debería ser.

Entonces, para resumir, si typeEncoding = float funciona, si es un doble, el resultado no se establece pero lee correctamente la variable y el valor de retorno (Ivar) también es correcto.

Debo estar haciendo algo básico que no puedo ver, así que agradecería si alguien pudiera señalarlo.

¿Fue útil?

Solución

object_getInstanceVariable es una pequeña función confusa. Es documentó que el último parámetro es un parámetro void ** & # 8212; es decir, pasa la dirección de una variable void * y obtiene un puntero a la variable de instancia & # 8212; pero se implementa como si fuera un parámetro void * & # 8212; es decir, pasa la dirección de la variable que desea que contenga una copia de la variable de instancia . El problema es que la implementación ignora el tamaño de la variable de instancia y solo hace una copia del puntero. Entonces, cualquier cosa que tenga el mismo tamaño que un puntero funcionará perfectamente. Si está ejecutando una arquitectura de 32 bits, solo se copiarán los 32 bits altos. (También debería ser testigo del mismo comportamiento con una variable de instancia long long ).

La solución es usar la API primaria, codificación de clave-valor , usando -valueForKey: .

La otra solución: si quisiera escribir una versión fija, digamos como una categoría para NSObject, se vería así:

@implementation NSObject (InstanceVariableForKey)

- (void *)instanceVariableForKey:(NSString *)aKey {
    if (aKey) {
        Ivar ivar = object_getInstanceVariable(self, [aKey UTF8String], NULL);
        if (ivar) {
            return (void *)((char *)self + ivar_getOffset(ivar));
        }
    }
    return NULL;
}

@end

Entonces su código se vería así:

double myDoubleValue = *(double *)[self instanceVariableForKey:@"someDouble"];

Otros consejos

¿Qué pasa con el uso de valueForKey :?

NSNumber * value = [self valueForKey:[NSString stringWithUTF8String:ivar_getName(tmpIvar)]];
NSLog(@"Double value: %f", [value doubleValue];

Nota: esto requiere que tenga un " someFloat " método. Si desea utilizar setValue: forKey :, también necesitará el " setSomeFloat: " método. Esto se implementa fácilmente declarando el ivar como @property y sintetizándolo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top