Question

J'ai object_getInstanceVariable qui fonctionne comme ici mais il semble que cela ne fonctionne que pour les floats, les bools et les ints, pas les doubles. Je soupçonne que je fais quelque chose de mal, mais je tourne en rond avec cela.

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

fonctionne et myFloatValue = 2.123

mais quand j'essaie

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

Je reçois myDoubleValue = 0 . Si je tente de définir myDoubleValue avant la fonction, par exemple. double myDoubleValue = 1.2f , la valeur n'est pas modifiée lorsque je la lis après l'appel object_getInstanceVariable . Définir myIntValue sur une autre valeur avant la fonction getinstancevar ci-dessus renvoie 2 comme il se doit, c'est-à-dire. il a été changé.

alors j'ai essayé

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

Si je le fais ivar_getName (tmpIvar) , j'obtiens "someDouble", mais myDoubuleValue = 0 quand même! Ensuite, j'essaie ivar_getTypeEncoding (tmpIvar) et j'obtiens "d". comme il se doit.

Donc, pour résumer, si typeEncoding = float , si cela est double, le résultat n'est pas défini, mais il lit correctement la variable et la valeur de retour (Ivar) est également correcte.

Je dois faire quelque chose de mal que je ne peux pas voir, alors j'apprécierais que quelqu'un me le signale.

Était-ce utile?

La solution

object_getInstanceVariable est une petite fonction confuse. C'est documenté que le dernier paramètre est un paramètre void ** & # 8212; en d'autres termes, vous transmettez l'adresse d'une variable void * et obtenez un pointeur à la variable d'instance & # 8212; mais elle est implémentée comme s'il s'agissait d'un paramètre void * & # 8212; c'est-à-dire que vous transmettez l'adresse de la variable sur laquelle vous souhaitez conserver une copie de la variable d'instance . Le problème est que l’implémentation ignore la taille de la variable d’instance et ne fait que copier le pointeur. Ainsi, tout ce qui a la même taille qu'un pointeur fonctionnera parfaitement. Si vous utilisez une architecture 32 bits, seuls les 32 bits les plus élevés seront copiés. (Vous devriez également observer le même comportement avec une variable d'instance long long .)

La solution consiste à utiliser l'API principale, codage valeur-clé , à l'aide de -valueForKey: .

L'autre solution: si vous vouliez écrire une version fixe, disons en tant que catégorie pour NSObject, cela ressemblerait à ceci:

@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

Ensuite, votre code ressemblerait à ceci:

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

Autres conseils

Qu'en est-il de l'utilisation de valueForKey:?

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

Remarque: pour cela, vous devez disposer d'un "someFloat". méthode. Si vous souhaitez utiliser setValue: forKey :, vous aurez également besoin de l'option " setSomeFloat: " méthode. Ceci est facilement implémenté en déclarant ivar comme propriété @ et en le synthétisant.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top