Подтвердить что ты не робот

Object_getInstanceVariable работает для float, int, bool, но не для double?

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

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) также корректно.

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

4b9b3361

Ответ 1

object_getInstanceVariable - путаница. documented, что последний параметр - это параметр 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

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

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

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