【问题标题】:free and malloc with NSValue and NSInvocationfree 和 malloc 与 NSValue 和 NSInvocation
【发布时间】:2012-03-14 17:47:05
【问题描述】:

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

- (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 会以某种方式自动处理吗?或者在这种情况下如何正确释放内存?

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    你必须免费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 没问题!在我编写测试应用程序之前,我个人也不知道答案!
    【解决方案2】:

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

    NSMutableData * dat = [NSMutableData dataWithLength:length];
    

    并以与 malloc'd 块相同的方式使用它

    void * buffer = [dat mutableBytes];
    

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

    如果此对象是短暂的并且不会进行大量此类分配,则名为 allocations 或类似名称的 NSMutableArray ivar 可以容纳所有 NSMutableData 实例,并且当其方法 this 的对象被释放。

    如果您愿意,可以使用associated objectsNSMutableData 的生命周期与NSValue 本身或NSInvocation 联系起来(视情况而定):

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

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

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

    【讨论】:

    • 看起来比完成后简单地释放缓冲区要麻烦得多,因为 NSValue 会复制您发送的缓冲区。
    猜你喜欢
    • 1970-01-01
    • 2012-06-10
    • 1970-01-01
    • 2012-08-29
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    相关资源
    最近更新 更多