为什么会破坏这个初始化器参数?

时间:2011-01-22 22:43:47

标签: objective-c debugging initialization argument-passing foundation

我有一个带有两个参数的初始化器:

-(id) initWithSourceFrame:(CGRect)sourceViewFrame  mappedFrame:(CGRect)mappedViewFrame {
  CGRect copy = mappedViewFrame;
  self = [super init];
  if (self) {
    // not able to access mappedViewFrame here..
    // copy is ok
    // doing initialization here...
  }
  return self;
}

它似乎从第二个参数(mappedViewFrame)得到错误的值。在查找错误时,我发现mappedViewFrame被破坏(在内存中被覆盖?)。 这可以在调试器中轻松观察到:

Debugger Screenshot on flickr (I cannot post images yet)

副本仍保留原始值,因此在这种情况下使用副本是一种解决方法。但我当然想知道为什么会发生这种情况。 该类是NSObject的直接子类,整个项目是OS X本机应用程序。 第一个论点从未被破坏过。这个问题与传入的值无关。我切换它们,它总是第二个被破坏的。

例如,我使用这些示例参数调用初始化程序(与调试程序屏幕截图中的参数不同),并且错误以相同的方式发生:

Mapper *mapper = [[Mapper alloc] initWithSourceFrame:CGRectMake(0, 0, 100, 100) mappedFrame:CGRectMake(0,0, 200,200)];

方法声明:

-(id) initWithSourceFrame:(CGRect) sourceViewFrame mappedFrame:(CGRect) mappedViewFrame;

我对Objective-C有点新鲜,所以如果我错过了一些明显的东西,我很抱歉。但是,在方法调用期间参数不能保持有效看起来很奇怪。

2 个答案:

答案 0 :(得分:1)

当我尝试使用NSLog而不是调试器重现错误时,我偶然发现了一个可能的解决方案。

有趣的是,记录的值是正确的。在调用NSLog之前,调试器仍然显示截图中的垃圾输出。但在访问值后(通过NSLog或其他程序访问),调试器会显示正确的值。

因此它看起来更像是调试器的问题。如果分配了某些对象,则更有可能出现错误的值显示。

仍然是个问题:为什么我的程序不起作用?我现在删除了'copy'变量(来自第2行)并直接访问mappedViewFrame,一切都按预期工作。所以现在之前没有工作的相同代码有效,我认为这可能有两个原因:

  1. 我的实现中出现了另一个错误,导致错误的计算结果。在引入'copy'变量时(在看到奇怪的调试器输出之后),我修复了另一个错误而没有注意到。之后,我将修复归功于我的新复制解决方案。

  2. 一个未知因素导致变量在我第一次遇到问题时失真,现在却没有。好吧,为了保持谨慎,我把副本留在那里,检查价值是否保持不变。如果发生这种情况,我会在这里发布。在那之前,第一个理论更有可能。

  3. 这件事告诉我不要相信调试器,而是在有疑问时使用日志记录,这很痛苦。如果有人知道是什么原因导致奇怪的调试器输出或如何解决它我会非常感兴趣。如果我有时间,我会进一步研究它何时出现,如果它只是在xcode中发生,或者是一般的gnu调试器的问题。

答案 1 :(得分:0)

我已经在几分钟内快速尝试过了。我从来没有真正尝试创建一个Mac OS X项目,只是创建了Foundation和iPhone项目,但这个想法似乎是一样的。我创建了一个Cocoa应用程序项目“Stack1”。我假设你已经做了同样的事情,因为我不认为一个Foundation项目会支持CGRect结构而不需要手动导入CGGeometry.h或者其他东西......无论如何,我设置了一个名为“Mapper”的新Objective C类并实现了您指定的initWithSourceFrame:mappedFrame:方法。

<强> Mapper.h

#import <Cocoa/Cocoa.h>

@interface Mapper : NSObject {

}

-(id) initWithSourceFrame:(CGRect) sourceViewFrame mappedFrame:(CGRect) mappedViewFrame;

@end

<强> Mapper.m

#import "Mapper.h"

@implementation Mapper

-(id) initWithSourceFrame:(CGRect)sourceViewFrame  mappedFrame:(CGRect)mappedViewFrame {
    NSLog(@"height: %f, width: %f", mappedViewFrame.size.height, mappedViewFrame.size.width);
    self = [super init];
    NSLog(@"height: %f, width: %f", mappedViewFrame.size.height, mappedViewFrame.size.width);
    if (self) {
        NSLog(@"height: %f, width: %f", mappedViewFrame.size.height, mappedViewFrame.size.width);
    }
    return self;
}

@end

我没有改变Stack1AppDelegate.h。

<强> Stack1AppDelegate.m

#import "Stack1AppDelegate.h"
#import "Mapper.h"

@implementation Stack1AppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application 
    Mapper *mapper = [[Mapper alloc] initWithSourceFrame:CGRectMake(0, 0, 100, 100) mappedFrame:CGRectMake(0,0, 200,200)];

}

@end

我的所有代码都是像你那样分配一个Mapper实例,并且在[super init]之后,[super init]之后以及if(self)块中使用NSLog打印宽度和高度。

这是日志:

2011-01-23 16:09:07.167 Stack1[935:a0f] height: 200.000000, width: 200.000000
2011-01-23 16:09:07.170 Stack1[935:a0f] height: 200.000000, width: 200.000000
2011-01-23 16:09:07.170 Stack1[935:a0f] height: 200.000000, width: 200.000000

我也在这里上传了整个项目:

http://ak.net84.net/files/temp/Stack1.zip