tranvutuan
tranvutuan

Reputation: 6109

leaking memory issue, memory management

What I am having now is

classA.h

@interface ClassA: NSObject <DelegateA>
-(id)initWithData:(NSData*)data;
+(Stores*)makeClass:(Class) name fromData:(NSData*)data;
@property (assign) NSMutableArray    *arr;
@property (assign) RXMLElement       *rxmlRoot;
@end

classA.m

   -(id)initWithData:(NSData*)data { 
        self = [super init]; 
        if (self) { 
            arr      = [[NSMutableArray array] retain]; 
            rxmlRoot = [[RXMLElement elementFromXMLData:data] retain]; 

        } 

        [rxmlRoot iterate:node with:^(RXMLElement *e){   <--------get warning at here
            NSLog(@"element is %@",e.tag);
            Detail   *detail  =   [[[Detail alloc] init] autorelease];
            [detail setLat:       [e attribute:@"lat"]];
            [detail setLon:       [e attribute:@"lon"]];

            [arr addObject:detail];

        }];
        return self; 
        }

      +(classA*)makeClass:(Class) name fromData:(NSData*)data{
            ClassA  *classA =   [[ClassA alloc] initWithData:data];
            return [storeClass autorelease] ;

        }

and RaptureXML.m

+ (id)elementFromXMLData:(NSData *)data {
    return [[[RXMLElement alloc] initFromXMLData:data] autorelease];
}
- (id)initFromXMLData:(NSData *)data {
    if ((self = [super init])) {
        xml_ = [[TBXML alloc] initWithXMLData:data];
        tbxmlElement_ = xml_.rootXMLElement;
    }

    return self;    
}

Warning : Instance variable access( via 'self') results in a null pointer dereference

Question : why I am getting this warning and how to fix this issue. Please advice me on this. Thanks

Upvotes: 0

Views: 294

Answers (3)

Patrick Borkowicz
Patrick Borkowicz

Reputation: 1216

Try putting all your initialization code in the

if (self) {

}

that is move the [rxmlrRoot itertate...etc. into that if statement

As a general rule, all initialization syntax (everything in the init method!) should be in that if (self) block. The reason is code outside that block would run when the super class returned nil (think else if (!self) {...). You don't want the code to continue executing if the super method (an initializer is just a regular method in O-C) was not called.

I was also taught to always have a designated initializer in my custom classes (this is the one that gets to call super init), all other initialzers in my class then call this designated initializer. Ex.

// Designated initializer
- (id)init
{
    self = [super init];
    if (self) {
        // initialize some stuff
    }

    // else { something went wrong and super returned nil..
    // don't put anything here

    return self;
}

// Another initializer
- (id)initWithFoo:(int)foo
{
    self = [self init]; // Now i call my designated initializer instead of super
    if (self) {
        self.foo = foo; // or something
    }
}

That allows you to control all the traffic from that one point.

Upvotes: 1

monoxygen
monoxygen

Reputation: 463

Inside the block, the instance variable arr is being accessed by reference. Due to subtle memory management rules, the access causes self to be retained by the block.

Since if (self) is a clue to the compiler that self may be nil, then the implicit retain of self by the block could cause a null pointer dereference.

To fix, check for nil and exit early:

if (!(self = [super init])) {
    return nil;
}

// now it is impossible for self to be nil and cause a null pointer dereference
// when self is implicitly retained by the block

// ...continue initialization

Upvotes: 0

Jeffery Thomas
Jeffery Thomas

Reputation: 42588

In the call [rxmlRoot iterate:node with:^(RXMLElement *e){ ... }], what is node? It is not a local variable, or an iVar. Is it a global or does it exist somewhere else?

What ever it is, check to make sure this has been initialized.

Upvotes: 0

Related Questions