Nik
Nik

Reputation: 9462

Objective-C dynamic object creation memory issue

I've been putting on with a strange issue in my iPhone program for a while.

To make long story short: I have an XML which contains data about tree-like composition. I've wrote a parser which constructs a tree from the XML.

Somewhere in DataSource class I have following method:

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

Factory method looks like this:

+ (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;
}

Also when I stop GDB on line where I call alloc and init methods and try to call them in debugger I see next error log:

(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.

So the situation is: somehow my program starts up and displays values that I need correctly. But when I try to do something with my component, program just crashes. Any ideas? How can I find a error? I don't any reasons why NSLog(@"created %@", component); crashes application and so do other actions with component (actually I want to encode it to an archive).

Thanks in advance!


Update

This is piece of factory method code with comments

+ (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 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.

Since this happens I want to make sure that all init methods are correct. Here what I am doing:

first - check that name of class is ConfigElement - yes

second - look at ConfigElement init - everything ok:

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

third - look at super (Composite) initializer:

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

then look for super initializer again (Component initializer now) - seems good again:

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

Since Component is a subclass of NSObject I don't need to bother about super initializer again and could probably remove if statement but let it be. Also all these initilizers are designated and they are actually called at the moment of init.

So why I am getting that error msg in GDB?

Upvotes: 2

Views: 654

Answers (2)

Nik
Nik

Reputation: 9462

The problem was in my buggy description method:

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

Once this method was fixed, debugger started to print correct values.

Upvotes: 2

bbum
bbum

Reputation: 162722

Both componentWithRoot: and loadAllData should be returning an autoreleased object.

What toiletseat said are all good suggestions/questions. This sounds specifically like a problem internal to your Component class. Would have to see its innards to say more.

Upvotes: 0

Related Questions