NSValue:getValue:奇怪的行为,为什么会这样?

时间:2011-08-12 07:03:57

标签: objective-c nsinvocation

我尝试将CGRect传递给NSInvocation(setArgument:atIndex :)。我用NSValue包装它,推送到NSArry,然后从NSArray获取并使用NSValue(getValue :)。调用(getValue :)方法会导致声明索引NSInteger i之前的更改。任何人都可以说为什么会这样?

 NSString className = @"UIButton";
    Class cls = NSClassFromString(className);
    cls pushButton5 = [[cls alloc] init];
    CGRect rect =CGRectMake(20,220,280,30);
    NSMethodSignature *msignature1;
    NSInvocation *anInvocation1;

    msignature1 = [pushButton5 methodSignatureForSelector:@selector(setFrame:)];
    anInvocation1 = [NSInvocation invocationWithMethodSignature:msignature1];

[anInvocation1 setTarget:pushButton5];
[anInvocation1 setSelector:@selector(setFrame:)];
NSValue* rectValue = [NSValue valueWithCGRect:rect];
NSArray *params1;
params1= [NSArray arrayWithObjects:rectValue,nil];
id currentVal = [params1 objectAtIndex:0];
NSInteger i=2;
if ([currentVal isKindOfClass:[NSValue class]]) {
    void *bufferForValue;
    [currentVal getValue:&bufferForValue];
    [anInvocation1 setArgument:&bufferForValue atIndex:i];
}else {
    [anInvocation1 setArgument:&currentVal atIndex:i];
}
[anInvocation1 invoke];

当这个(getValue:)方法实现'i'的值从2变为类似:1130102784时,在(setArgument:atIndex:)中我有一个SIGABRT因为索引i超出界限。

那么为什么[NSValue getValue:(*void) buffer]会改变其他变量?

(P.S。我在函数中这样做,所以我简化了一个例子并直接初始化数组。 如果我直接设置在索引:2,它工作得很完美。但是我很难过,我简化了一点,我需要将i传递给atIndex:)


感谢Tom Dalling(特别是)和塞尔吉奥问题解决了。我删除了这个:

void *bufferForValue;
[currentVal getValue:&bufferForValue];
[anInvocation1 setArgument:&bufferForValue atIndex:i];

并粘贴此

NSUInteger bufferSize = 0;
NSGetSizeAndAlignment([currentVal objCType], &bufferSize, NULL);
void* buffer = malloc(bufferSize);
[currentVal getValue:buffer];
[anInvocation1 setArgument:buffer atIndex:i];

谢谢。 Stackoverflow.com真的很有帮助的网站与聪明的人。

2 个答案:

答案 0 :(得分:8)

您无法将NSRect纳入void*。正确的代码是:

NSRect buffer;
[currentVal getValue:&buffer];

或者,如果您不知道NSValue对象的内容:

NSUInteger bufferSize = 0;
NSGetSizeAndAlignment([currentVal objCType], &bufferSize, NULL);
void* buffer = malloc(bufferSize);
[currentVal getValue:buffer]; //notice the lack of '&'
//do something here
free(buffer);

i的值正在改变,因为您的代码会导致其他堆栈分配的变量溢出。

答案 1 :(得分:2)

在:

 void *bufferForValue;
 [currentVal getValue:&bufferForValue];

您正在将currentVal值复制到大小为void*(指针)的缓冲区;现在,请参阅getValue reference

  

的getValue:

     

将接收者的值复制到给定的缓冲区中。

     

缓冲

     

复制接收者值的缓冲区。缓冲区必须足够大才能保存该值。

由于复制到缓冲区的值不适合void*,因此您将覆盖堆栈,因为您正在写入局部变量的地址;这可能会覆盖i局部变量,因此可以解释发生了什么。