当属性具有自定义命名的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会以某种方式自动处理吗?或者在这种情况下如何正确释放内存?
答案 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
)保留数据对象,并在解除分配时释放它。