【问题标题】:NSValue:getValue: strange behavior,why this happens?NSValue:getValue: 奇怪的行为,为什么会这样?
【发布时间】:2011-08-12 07:03:56
【问题描述】:

我尝试将 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];

当 this(getValue:) 方法实现 'i' 的值从 2 更改为:1130102784 时,在(setArgument:atIndex:) 中我有一个 SIGABRT,因为索引 i 超出范围。

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

(P.S. 我是在函数中做的,所以我简化了一个例子并直接初始化数组。 如果我直接设置atIndex:2,它就完美了。但是我很伤心我简化了一点,我需要将i传递给atIndex :)


感谢 Tom Dalling(特别是)并解决了 sergio 问题。我删除了这个:

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 对聪明人很有帮助的网站。

【问题讨论】:

    标签: objective-c nsinvocation


    【解决方案1】:

    您不能将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 的值正在更改,因为您的代码导致溢出到其他堆栈分配的变量中。

    【讨论】:

    • 谢谢汤姆。你是对的,但不幸的是,它只部分解决了我的问题,因为实际上我不知道 NSArray 的参数类型。
    • 我没试过,但显然你可以用这个得到一个 NSValue 值的大小:forums.macnn.com/79/developer-center/131643/…
    • 汤姆!你是我的救星!非常感谢,现在它可以正常工作,并且没有任何堆栈覆盖。你真的帮了我。再次感谢。
    • 感谢它的帮助,但是如何将 void* 缓冲区转换为 C++ 类?
    • 了解dynamic_cast<#type#>(#expression#)static_cast<#type#>(#expression#)
    【解决方案2】:

    在:

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

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

    获取值:

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

    缓冲区

    将接收者的值复制到其中的缓冲区。缓冲区必须足够大以容纳该值。

    由于您复制到缓冲区的值无法放入void*,因此您正在覆盖堆栈,因为您正在写入局部变量的地址;这可能会导致覆盖 i 局部变量,从而解释发生了什么。

    【讨论】:

    • bufferForValue 未初始化,但&bufferForValue 是指向堆栈分配内存的有效指针。他的问题是sizeof(void*)小于sizeof(NSRect)
    • @Tom Dalling:你是对的,谢谢。我从我的答案中删除了对未初始化缓冲区的引用。为您的回答 +1。
    猜你喜欢
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    相关资源
    最近更新 更多