object_getInstanceVariable работает для float, int, bool, но не для double? - PullRequest
12 голосов
/ 02 августа 2009

У меня есть object_getInstanceVariable, чтобы работать как здесь , но, похоже, это работает только для чисел с плавающей запятой, bools и int, а не удваивается. Я подозреваю, что делаю что-то не так, но я ходил кругами с этим.

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

работает, а myFloatValue = 2.123

но когда я пытаюсь

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

Я получаю myDoubleValue = 0. Если я пытаюсь установить myDoubleValue перед функцией, например. double myDoubleValue = 1.2f, значение не изменяется, когда я читаю его после вызова object_getInstanceVariable. Установка myIntValue в другое значение до того, как вышеприведенная функция getinstancevar вернет 2, как и должно быть, т.е. оно было изменено.

тогда я попробовал

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

Если я сделаю ivar_getName(tmpIvar), я получу "someDouble", но myDoubuleValue = 0 все же! Затем я пытаюсь ivar_getTypeEncoding(tmpIvar), и я получаю "d", как и должно быть.

Таким образом, если подвести итог, если typeEncoding = float, это работает, если это двойное число, результат не установлен, но он правильно читает переменную, и возвращаемое значение (Ivar) также корректно.

Я, должно быть, делаю что-то не так, что не вижу, поэтому буду признателен, если кто-нибудь это укажет.

Ответы [ 2 ]

29 голосов
/ 03 августа 2009

object_getInstanceVariable - маленькая запутанная функция. задокументировано , что последний параметр является параметром void **, то есть вы передаете адрес переменной void * и получаете указатель на переменную экземпляра, но он реализован так, как если бы параметр void * - то есть вы передаете адрес переменной, в которой хотите хранить копию переменной экземпляра. Проблема в том, что реализация игнорирует размер переменной экземпляра и просто копирует указатель. Так что все, что имеет такой же размер, как указатель, будет работать отлично. Если вы работаете в 32-битной архитектуре, будут скопированы только старшие 32 бита. (Вы должны наблюдать такое же поведение и с переменной экземпляра long long.)

Решение состоит в том, чтобы использовать первичный API, кодирование значения ключа , используя -valueForKey:.

Другое решение: если вы хотите написать фиксированную версию, скажем, как категорию для NSObject, она будет выглядеть примерно так:

@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

Тогда ваш код будет выглядеть так:

double myDoubleValue = *(double *)[self instanceVariableForKey:@"someDouble"];
2 голосов
/ 02 августа 2009

Как насчет использования valueForKey:?

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

Примечание: для этого требуется метод someFloat. Если вы хотите использовать setValue: forKey:, вам также понадобится метод "setSomeFloat:". Это легко реализовать, объявив ivar как @property и синтезировав его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...