为什么传值的struct参数被破坏了?

时间:2010-11-12 00:54:13

标签: objective-c debugging

这不是原始代码(我在试图简化调试时剥离了东西),但它确实显示了问题。从表面上看,看起来很简单:

- (void) testMethod: (TouchData) toi  {

     TouchData newToi = toi;
     NSString *test = @"test string";
     NSLog(@"string: %@", test);

     // in ‘real’ code I pass the struct back
     // It’s void here for the simplest possible
     // case
}

TouchData是一个结构,声明如下:

typedef struct {
    Entity *owner;
    CGPoint startPos;
    CGPoint latestPos;
    CGPoint startOfStraightSwipePos;
    NSTimeInterval startTime;
    NSTimeInterval latestTime;
    NSTimeInterval startOfStraightSwipeTime;
    CGFloat latestSpeed;
    NSMutableArray *gestures;
    BOOL isOfInterest;
} TouchData;

当我在调试器中逐步执行testMethod(观察toi)击中NSLog (甚至不涉及toi)时,所有toi成员值突然变为零。这不会发生在副本(newToi)上。如果我通过引用传递struct,就不会发生这种情况。如果直接用方法体替换testMethod调用就不会发生(即,如果我在原地运行这些行而不是调用方法)。如果我将toi参数类型更改为具有在调用之前创建的几个int成员的虚拟结构,则不会发生这种情况。

值得指出的是,testMethod只能从它自己的内部调用 class,并且调用者刚从NSMutableDictionary中提取结构(通过拆箱NSValue)。但鉴于(a)结构是 这里通过值传递给方法,(b)在进入其成员时如图所示 通过调试器都是预期的,我没有看到这可能导致问题。结构中的两个对象指针也存在棘手的问题,但在其他情况下它们正在运行正常,并且它们在调试器中检查进入该方法,所以我认为我没有错过必要的保留

我认为我遇到了某种堆或堆栈损坏,但我不知道如何或为什么。我是Objective-C的新手,之前曾在这里工作过 垃圾收集环境,所以我的内存管理经验有限。我完全有可能错过了一些非常明显的东西。

我希望有人会告诉我让TouchData成为一种对象类型,事实上我可能会这样做。我还有一些经过测试的解决方法,即。要么在副本上工作,要么通过ref传递结构。但我真的很想知道这里发生了什么。

1 个答案:

答案 0 :(得分:2)

如果在toi行之后没有使用TouchData newToi=toi,编译器可以在堆栈内存中执行任何操作,其中toi最初位于该行之后。例如,它可能在调用另一个函数时重用堆栈内存,在本例中为NSLog

因此,通过调试器观看toi可能会显示一些奇怪的内容。编译器通常会执行这些操作,尤其是在启用优化的情况下。即使没有优化,也无法保证toi的堆栈位置在上次使用后保持不变。

顺便说一句,你说在toi内有对象指针并没有引起问题,但这是一个棘手的情况,我强烈反对这种做法。遵循标准保留/释放规则;否则,另一个看了你的代码的程序员(从现在起两年后可能就是你自己)会完全混淆。此外,静态分析器(可以通过在XCode中进行Build& Analyze访问)可能会混淆并可能产生误报。所以,不要这样做。