free и malloc с NSValue и NSInvocation - PullRequest
3 голосов
/ 14 марта 2012

Я делаю утилиту для получения / установки значений свойств, когда свойство имеет геттеры и сеттеры с произвольным именем.Вы можете увидеть полный контекст в строке 279 здесь .Соответствующий фрагмент приведен здесь:

- (id) getFrom:(id) object {
    NSMethodSignature *methodSig = [[object class] instanceMethodSignatureForSelector:[self getter]];
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSig];
    [inv setSelector:[self getter]];
    [inv setTarget:object];
    [inv invoke];

    if ([self isObject]) {
        id returnValue;
        [inv getReturnValue:&returnValue];
        return returnValue;
    } else {
        void *buffer;
        NSUInteger length = [methodSig methodReturnLength];
        buffer = (void *)malloc(length);
        [inv getReturnValue:buffer];
        NSValue *value = [NSValue valueWithBytes:buffer objCType:[methodSig methodReturnType]];
        //FIXME: Memory leak for buffer!  But if we free it, [value getValue:] is a dangling pointer.
        //free(buffer)
        return value;
    }
}    

Проблема в том, что когда свойство является скалярным, я хочу вернуть значение NSValue (во многом как кодирование значения ключа).Однако возвращаемое значение для NSInvocation возвращается по ссылке, и согласно документации Apple (см. Внизу) я не могу освободить память, связанную со скаляром, пока NSValue все еще существует - но явозвращаю NSValue, поэтому я не знаю, когда освободить память.

Я неправильно читаю документацию?NSValue обрабатывает это как-то автоматически?Или как мне правильно освободить память в этой ситуации?

Ответы [ 2 ]

0 голосов
/ 14 марта 2012

Я бы предложил использовать NSMutableData вместо malloc().Вы можете выделить некоторую память

NSMutableData * dat = [NSMutableData dataWithLength:length];

и использовать ее так же, как если бы malloc 'd chunk

void * buffer = [dat mutableBytes];

Теперь dat владеет памятью, что помещает ее подобычная схема пересчета какао.С этой точки вы можете сделать одну из двух вещей.

Если этот объект недолговечный и не будет выполнять много таких распределений, NSMutableArray ивар с именем allocations или аналогичный может содержать все экземпляры NSMutableData, и они будутосвобождается, когда объект, чей метод это является, освобождается.

Если хотите, вы можете привязать жизнь NSMutableData либо к NSValue, либо к NSInvocation, в зависимости от ситуации, используя связанные объекты :

objc_setAssociatedObject(value, &dat_key, dat, OBJC_ASSOCIATION_RETAIN);

Где dat_key - это объявленная поблизости переменная static, чей адрес вы используете (как рекомендуют документы).

Этозаставляет ассоциатор (value в данном случае) сохранять объект данных и освобождать его, когда он сам освобождается.

0 голосов
/ 14 марта 2012

Вы должны освободить buffer. +valueWithBytes:objCType: копирует отправленный буфер, поэтому по окончании вы можете освободить буфер.

Вы также можете дополнительно использовать объект NSData, например:

NSData *data = [[NSData alloc] initWithBytesNoCopy:buffer length:length freeWhenDone:YES]; 

Это будет означать, что когда объект NSData будет освобожден, то же самое произойдет и с созданным вами буфером.

Доказательство того, что +valueWithBytes:objCType: копирует буфер:

int *buffer = malloc(sizeof(int));
buffer[0] = 50;

NSValue *value = [NSValue valueWithBytes:buffer objCType:@encode(int)];

// sribble 'buffer'
buffer[0] = 1000;
free(buffer);

int test = 1000;
[value getValue:&test];

printf("%i", test);  // outputs 50
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...