问题
I try to pass CGRect to NSInvocation (setArgument:atIndex:). I wrap it by NSValue, push to the NSArry,then get from NSArray and use NSValue (getValue:). Calling of (getValue:) method causes the changing of before declared index NSInteger i. Can anybody say why does this happen?
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:¤tVal atIndex:i];
}
[anInvocation1 invoke];
When this(getValue:)
method implements value of 'i' changes from 2 to something like : 1130102784, and in (setArgument:atIndex:)
I have an SIGABRT because index i is out of bounds.
So why does [NSValue getValue:(*void) buffer]
change other variables?
(P.S. I do it in function so I simplified an example and initialize array directly. And if I set directly atIndex:2, It works perfect.But as I've sad I simplified a little, and I need to pass i to atIndex:)
Thanks to Tom Dalling(especially) and sergio problem solved. I delete this:
void *bufferForValue;
[currentVal getValue:&bufferForValue];
[anInvocation1 setArgument:&bufferForValue atIndex:i];
and paste this
NSUInteger bufferSize = 0;
NSGetSizeAndAlignment([currentVal objCType], &bufferSize, NULL);
void* buffer = malloc(bufferSize);
[currentVal getValue:buffer];
[anInvocation1 setArgument:buffer atIndex:i];
Thank you. Stackoverflow.com really helpful site with smart people.
回答1:
You can't fit an NSRect
into a void*
. The correct code would be:
NSRect buffer;
[currentVal getValue:&buffer];
Or alternatively, if you don't know the contents of the NSValue
object:
NSUInteger bufferSize = 0;
NSGetSizeAndAlignment([currentVal objCType], &bufferSize, NULL);
void* buffer = malloc(bufferSize);
[currentVal getValue:buffer]; //notice the lack of '&'
//do something here
free(buffer);
The value for i
is changing because your code causes an overflow into other stack-allocated variables.
回答2:
In:
void *bufferForValue;
[currentVal getValue:&bufferForValue];
you are copying currentVal
value to a buffer which has the size of void*
(a pointer); now, see getValue reference:
getValue:
Copies the receiver’s value into a given buffer.
buffer
A buffer into which to copy the receiver's value. buffer must be large enough to hold the value.
Since the value you copying over to the buffer cannot fit in a void*
, you are thus overwriting your stack, since you are writing to the address of a local variable; this has likely the effect of overwriting the i
local variable, so that explains what is happening.
来源:https://stackoverflow.com/questions/7036665/nsvaluegetvalue-strange-behavior-why-this-happens