Objective-C动态对象创建内存问题

时间:2011-04-05 14:12:34

标签: iphone objective-c memory-management

我已经在iPhone程序中遇到了一个奇怪的问题。

简而言之:我有一个XML,其中包含有关树状组合的数据。我编写了一个解析器,它从XML构造一个树。

在DataSource类的某处我有以下方法:

 - (id)loadAllData {
   if (self.doc != nil) {
    GDataXMLElement *root = [self.doc rootElement];
    Component *component = [Component componentWithRoot:root];
    NSLog(@"%@", component);
    return component;
  }
  return nil;
}

工厂方法如下所示:

+ (id)componentWithRoot:(GDataXMLNode*)element {
  id<iComponent> component = nil;
  NSString *clsName = [NSString stringWithFormat:@"%@Element", [element name]];

  // Will return instance of a class or |nil| if class is not loaded.
  Class cls = NSClassFromString(clsName);

  if (cls != nil) {
    component = [[cls alloc] init];

    // dies on next line
    NSLog(@"created %@", component);

    // Seems that we have corresponding model class
    if (component != nil) {

      //... setting attrubutes for this model

      //... trying to find child elements and add them to the component instance.
    }
  }
  return component;
}

当我在线上停止GDB,我调用allocinit方法并尝试在调试器中调用它时,我会看到下一个错误日志:

(gdb) po component

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x828282df
0x01052a67 in objc_msgSend ()
The program being debugged was signaled while in a function called from GDB.
GDB has restored the context to what it was before the call.
To change this behavior use "set unwindonsignal off"
Evaluation of the expression containing the function (_NSPrintForDebugger) will be abandoned.

所以情况是:我的程序以某种方式启动并显示我需要的值。但是当我尝试用我的component做某事时,程序就崩溃了。有任何想法吗?我怎么能找到错误?我没有任何原因导致NSLog(@"created %@", component);崩溃应用程序,因此使用component执行其他操作(实际上我想将其编码为存档)。

提前致谢!


更新

这是带注释的工厂方法代码

+ (id)componentWithRoot:(GDataXMLNode*)element {
  id<iComponent> component = nil;
  NSString *clsName = [NSString stringWithFormat:@"%@Element", [element name]];
  NSLog(@"%@", clsName);
  // Will return instance of a class or |nil| if class is not loaded.
  Class cls = NSClassFromString(clsName);
  if (cls != nil) {
    component = [[[cls alloc] init] autorelease];
    // Seems that we have corresponding model class
    if (component != nil) {

      [component setTitle:[element name]]; 
      /*
       when I run app I have first element named ConfigElement. 
       Code runes fine to this point and even properties are set correct.
       But if I set breakpoint at this line and type in consle 
         po component
       I get message which is posted below
      */ 

(gdb)po组件

程序收到信号EXC_BAD_ACCESS,无法访问内存。 原因:地址为KERN_INVALID_ADDRESS:0x828282df objc_msgSend()中的0x01052a67 正在调试的程序在从GDB调用的函数中发出信号。 GDB已将上下文恢复到调用之前的状态。 要更改此行为,请使用“set unwindonsignal off” 评估包含该函数的表达式(_NSPrintForDebugger)将被放弃。

由于这种情况发生,我想确保所有init方法都正确。 这就是我在做什么:

首先 - 检查班级名称是ConfigElement - 是

第二 - 看看ConfigElement init - 一切正常:

- (id)init {
  self = [super init];
  return self;
} 

第三 - 查看超级(Composite)初始值设定项:

- (id)init {
  if ((self = [super init])) {
    children_ = [[NSMutableArray alloc] init];
  }
  return self;
}

然后再次查找超级初始化程序(现在Component初始化程序) - 再次看起来很好:

- (id)init {
  if ((self=[super init])) {
    title_ = nil;
    name_ = nil;
    icon_ = nil;
    parent_ = nil;
    children_ = nil;
  }
  return self;  
}

由于Component是NSObject的子类,我不需要再次关注超级初始化器,并且可能会删除if语句但是让它成为。此外,所有这些启动器都被指定,它们实际上是在init时调用的。

那么为什么我在GDB中收到错误消息?

2 个答案:

答案 0 :(得分:2)

问题出在我的错误description方法中:

- (NSString*)description {
  NSString *desc = [NSString stringWithFormat:@"Title: %@, Name: %@, Icon: %@, parent: %@, children: %@", self.title, self.name, self.icon, self.parent];
  return desc;
}

修复此方法后,调试器开始打印正确的值。

答案 1 :(得分:0)

componentWithRoot:loadAllData都应返回autorelease d对象。

toiletseat 所说的都是很好的建议/问题。这听起来特别像是Component课程内部的问题。必须看到它的内脏才能说更多。