views:

130

answers:

2

Hello all ,

I have developed my iPhone application and now I am testing it with instruments to find memory leakages .

I have my appDelegate class in which I am fetching data from web service and then parse it then store it in an array..

Here is my applicationDidFinishLaunching method :

UIApplication* app = [UIApplication sharedApplication]; 
app.networkActivityIndicatorVisible = YES; 
serviceURL = [[NSUserDefaults standardUserDefaults] stringForKey:@"readOnly_key"];
NSLog(@"text = %@",serviceURL);

if(serviceURL == nil)
{
 //We set the default values from the settings bundle.

 //Get the bundle path
 NSString *bPath = [[NSBundle mainBundle] bundlePath];
 NSString *settingsPath = [bPath stringByAppendingPathComponent:@"Settings.bundle"];
 NSString *plistFile = [settingsPath stringByAppendingPathComponent:@"Root.plist"];

 NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFile];
 NSArray *preferencesArray = [settingsDictionary objectForKey:@"PreferenceSpecifiers"];

 NSDictionary *item;

 NSString *textEntry_Key;
 NSString *readOnly_Key;


 for(item in preferencesArray)
 {
  //Get the key of the item.
  NSString *keyValue = [item objectForKey:@"Key"];

  //Get the default value specified in the plist file.
  id defaultValue = [item objectForKey:@"DefaultValue"];

  if([keyValue isEqualToString:@"textEntry_key"]){
   textEntry_Key = defaultValue;

  }

  NSLog(@"default value = %@",defaultValue);
  if([keyValue isEqualToString:@"readOnly_key"])
   readOnly_Key = defaultValue;



 }

 //Now that we have all the default values.
 //We will create it here.
 NSDictionary *appPrerfs = [NSDictionary dictionaryWithObjectsAndKeys:
          textEntry_Key, @"textEntry_key",
          readOnly_Key, @"readOnly_key",

          nil];

 [[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
 [[NSUserDefaults standardUserDefaults] synchronize];

}

NSURL *url5 = [[NSURL alloc] initWithString:@"http://192.168.0.150/Nirmal/Service.asmx/searchParameterList"];
//NSURL *url5 = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@/Service.asmx/searchParameterList"]];
NSMutableURLRequest* request6=[NSMutableURLRequest requestWithURL:url5];
[request6 setHTTPMethod:@"POST"]; 
[request6 setTimeoutInterval:10];
//NSURLResponse *response6=nil;
//  NSError *err6=nil;
    //NSData *data6=[[NSURLConnection sendSynchronousRequest:request6 returningResponse:&response6 error:&err6] retain];
    data2=[NSURLConnection sendSynchronousRequest:request6 returningResponse:nil error:nil];
    if(data2 == nil)
    {
     UIAlertView* alert = [[UIAlertView alloc]initWithTitle:@"Alert" message:@"The network is not available.\n Please check the Internet connection." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
     [alert show];
     [alert release];

    }
    else
    {
     NSXMLParser *xmlParser5 = [[NSXMLParser alloc] initWithData:data2];

     //Initialize the delegate.
     SearchParameterDataParser *searchParameterDataParser = [[SearchParameterDataParser alloc] initSearchParameterDataParser];

     //Set delegate
     [xmlParser5 setDelegate:searchParameterDataParser];

     //Start parsing the XML file.
     @try {
      // **the leakage line**
      BOOL success1 = [xmlParser5 parse];


      if(success1)
       NSLog(@"No Errors");
      else
       NSLog(@"Error Error Error!!!");
     }
     @catch (NSException * e) {
      NSLog(@"Exception in parsing %@  %@",[e name], [e reason]);
     }
     //[xmlParser5 release];
     [searchParameterDataParser release];
     //[xmlParser5 release]; //leakage
    }

    [data2 release];

and this is my parser class :

#import "SearchParameterDataParser.h"
#import "AppDelegate.h"
#import "SearchClass.h"

@implementation SearchParameterDataParser
-(SearchParameterDataParser *)initSearchParameterDataParser{
    [super init];
    appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    return self;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 
    attributes:(NSDictionary *)attributeDict {

    if([elementName isEqualToString:@"SearchClass"]) {
     [appDelegate.tempArray release];
     appDelegate.tempArray = [[NSMutableArray alloc] init];
     appDelegate.aSearchClass = [[SearchClass alloc]init];
    }


    NSLog(@"Processing Element: %@", elementName);
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { 

    if(!currentElementValue){


     [currentElementValue release];
     currentElementValue = [[NSMutableString alloc] initWithString:string];
    }
    else
     [currentElementValue appendString:string];

    NSLog(@"Processing Value: %@", currentElementValue);

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

    if([elementName isEqualToString:@"SearchClass"]){
     [appDelegate.tempArray addObject:appDelegate.aSearchClass];

     return;
    }
    else 
     [appDelegate.aSearchClass setValue:currentElementValue forKey:elementName];




//  [currentElementValue release];
    currentElementValue = nil;
}

- (void) dealloc {
    [super dealloc];    
    [aSearchClass release];
    [currentElementValue release];
    //[self release];

}
@end

I have specified the leakage line in the code .

Can anyone tell me what is going wrong or how can I solve the memory leakage ???????

+3  A: 

This is pretty messy, as a suggestion to clean things up a bit, try moving some memory management stuff to accessor methods - your code is littered with -release methods. ie,

instead of:-

if([elementName isEqualToString:@"SearchClass"]) {
    [appDelegate.tempArray release];
    appDelegate.tempArray = [[NSMutableArray alloc] init];
}

try:-

if([elementName isEqualToString:@"SearchClass"]) {

    appDelegate.tempArray = [NSMutableArray array];
}

where

appDelegate has a method

- (void)setTempArray:(NSMutableArray *)value {

    if(value!=tempArray){
     [tempArray release];
     tempArray = [value retain];
    }
}

or you can use a @synthesized accessor method to save coding it yourself. As an aside tempArray is a terrible name for an instance variable. Also note that you are releasing the old tempArray each time you make a new one - when does the last instance get cleaned up?

This is still not great as your parser class should not access directly the instance variables in appDelegate. Vardiables tempArray and searchClass should be private, but that is off the point and more of a design issue.

Where does url5 get released?

What is this supposed to do?

if(!currentElementValue){
    [currentElementValue release];
}

release currentElementValue if it doesn't exist?

[data2 release];

Did you retain data2?

- (void) dealloc {
[super dealloc];    
    [aSearchClass release];
    [currentElementValue release];
    //[self release];

}

i thought aSearchClass was an instance variable on appDelegate?

This might sound like nitpicking but it is much easier to track down leaks if make your code clear and you know exactly what is going on.

I know that tempArray is not a good name . but for now I have take in the appDelegate because I am loading all my data in applicationDidDinishLaunching so I am using that variable in the parser classand regarding to the [currentElementValue release];and [data2 release] , I have released as I don't know much about memory fixes but wherever I have redirected by the instruments I have tried to solve the leakage just by releasing the object as i think that it is not released .. If further suggestion you are welcome
hib
+1  A: 

You need to release both url5 and xmlParser5, since you've allocated them using alloc.

You should also be wary of calling release on properties, since the standard setters created when you @synthesize an instance variable typically release the previous value of the variable before setting the new value.

Nathan de Vries
youv are right on both url5 and xmlParse5 but another problem that I have not mentioned above is that whenever I tried to release the above objects the application crashes . See I have commented the release of xmlParser5
hib
If you call "release" on "xmlParse5" twice, your application will crash. You should call it once after you call "parse".
Nathan de Vries
I have called it just once . I was just trying before or after . Ignore the two places sorry for the wrong impression ..
hib