带有NSValue和NSInvocation的free和malloc

时间:2012-03-14 17:47:05

标签: objective-c

当属性具有自定义命名的getter和setter时,我正在创建一个实用程序来获取/设置属性值。您可以在第279行here查看完整的上下文。相关的片段在这里:

- (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(很像Key-Value编码)。但是,NSInvocation的返回值是通过引用返回的,并且根据the apple documentation(参见下图),当NSValue仍然存在时,我无法释放与标量关联的内存 - 但我将返回NSValue,所以我不知道何时释放内存。

我读错了文档吗? NSValue会以某种方式自动处理吗?或者在这种情况下如何正确释放内存?

2 个答案:

答案 0 :(得分:0)

您必须免费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

答案 1 :(得分:0)

我建议使用NSMutableData代替malloc()。你可以分配一些内存

NSMutableData * dat = [NSMutableData dataWithLength:length];

并以与malloc'dunk

相同的方式使用它
void * buffer = [dat mutableBytes];

现在dat拥有内存,将其置于通常的Cocoa引用计数方案之下。从这一点来说,你可以做两件事之一。

如果此对象是短暂的并且不会进行大量此类分配,则NSMutableArray名为allocations的{​​{1}} ivar可以容纳所有NSMutableData个实例,并且当释放其方法的对象被解除分配时,将被释放。

如果您愿意,可以使用associated objects视情况将NSMutableData的生命周期与NSValue本身或NSInvocation联系起来:

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

其中dat_key是附近声明的static变量,您正在使用其地址(正如文档推荐的那样)。

这使得关联器(在这种情况下为value)保留数据对象,并在解除分配时释放它。