使用NSValue和NSInvocation进行free和malloc

3

我正在制作一个实用程序,用于在属性具有自定义命名的getter和setter时获取/设置属性值。您可以在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的返回值是通过引用返回的,并且根据苹果文档(请参见底部的链接),我不能在NSValue仍然存在时释放与标量相关联的内存--但我正在返回NSValue,所以我不知道何时释放内存。
我是否错误阅读了文档?NSValue是否自动处理这个问题?或者在这种情况下如何正确地释放内存?
2个回答

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

啊,我一定是误读了苹果的文档。谢谢,这确实简化了事情! - jagill
@jagill 没问题!我个人写测试程序之前也不知道答案! - Richard J. Ross III

0

我建议使用NSMutableData而不是malloc()。你可以分配一些内存。

NSMutableData * dat = [NSMutableData dataWithLength:length];

并且您可以像使用malloc分配的块一样使用它

void * buffer = [dat mutableBytes];

现在dat拥有内存,这将使它处于通常的Cocoa引用计数方案下。从这一点出发,您可以做两件事情。

如果此对象的生命周期较短且不会进行大量此类分配,则称为allocations或类似名称的NSMutableArray ivar可以容纳所有NSMutableData实例,并且当包含此方法的对象被释放时,它们将被释放。

或者,您可以使用associated objectsNSMutableData的生命周期与NSValue本身或适当的NSInvocation绑定:

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

这里的dat_key是一个靠近声明的static变量,你正在使用它的地址(正如文档所建议)。

这使得关联器(在这种情况下是value)保留数据对象,并在自身被释放时释放它。


似乎比仅在完成后释放缓冲区要麻烦得多,因为NSValue会复制您发送的缓冲区。 - Richard J. Ross III

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接