?
Solved

IOS memory leak

Posted on 2012-09-05
11
Medium Priority
?
1,777 Views
Last Modified: 2012-09-08
Hi,

I have an iPad app that has been developed using Xcode 4.4.1. I am using ARC to manage memory.

When running the app through instruments (leaks) I seem to to be getting a leak on an NSDictionary object and also a related PerformSegueWithIdentifier method to the view that is leaking.

The NSDictionary is used in the ViewDidLoad method as shown below.

the leak occurs when the modal view is dismissed.

The leak occurs both in simulator and on the device.

I have also attached screen shot of instruments on the offending NSDictionary. I have scoured documentation and websites but cannot seem to find a solution. Any help gratefully received.

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view.
    
    [self.mapView setMapType:MKMapTypeStandard];
    [self.mapView setZoomEnabled:YES];
    [self.mapView setScrollEnabled:YES];
    
    self.mapView.delegate = self;
    
    coords.latitude = 53.800651;
    coords.longitude= -4.064941;
    
    region.center = coords;//self.mapView.userLocation.coordinate;  
    
    span.latitudeDelta  = 5;
    span.longitudeDelta = 5;
    
    region.span = span;
    
    [self.mapView setRegion:region animated:YES];
    
    NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"MapPins" ofType:@"plist"];
    self.locations = [NSDictionary dictionaryWithContentsOfFile:plistPath]; //leak here
    
    
    //loop through plist to add pins to map
    for (NSString *loc in self.locations) {
        
        //NSLog(@"loc: %@",loc);
        MKPointAnnotation *myAnnotation=[[MKPointAnnotation alloc]init];
        NSDictionary *value =[self.locations objectForKey:loc];
        
        myAnnotation.coordinate = CLLocationCoordinate2DMake(
                                                             [[value objectForKey:@"latitude"] doubleValue],
                                                             [[value objectForKey:@"longitude"] doubleValue]);
        myAnnotation.title = [value objectForKey:@"Title"];
        //myAnnotation.subtitle = [value objectForKey:@"subtitle"];
        
        //NSLog(@"%@",myAnnotation.title);
        [self.mapView addAnnotation:myAnnotation];
        
    }
    
}

Open in new window

instruments.tiff
instruments-segue.tiff
0
Comment
Question by:Strongs
  • 6
  • 5
11 Comments
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 38370857
I do not see a leak in the code you posted.
Maybe you have your own implementation of the 'locations' property? How you declare this property? It should be 'retain' (probably, strong in the project with ARC).

For a test you can make the following change:

  NSDictionary *places = [NSDictionary dictionaryWithContentsOfFile:plistPath]; //leak here
   //loop through plist to add pins to map
  for (NSString *loc in places) {
     // other code
  }
  places = nil;
 
If such code will "fix" the problem, add
[self setLocations:places];
before places = nil;
0
 

Author Comment

by:Strongs
ID: 38372311
Hi Pgnatyuk,

Thanks for posting a possible fix for this issue. I have tried what you suggested before posting but tried it again just in case. It doesn't fix the issue unfortunately.

The NSDictionary locations is declared as:

@property (strong, nonatomic) NSDictionary *locations;

I am wondering if this is an Xcode issue rather than a genuine leak?

Thanks for your help.
0
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 38373128
Please check the code in the loop:
 
 
self.locations = [NSDictionary dictionaryWithContentsOfFile:plistPath]; //leak here
    //loop through plist to add pins to map
    for (NSString *loc in self.locations) {
        
        //NSLog(@"loc: %@",loc);
        MKPointAnnotation *myAnnotation=[[MKPointAnnotation alloc]init];
        NSDictionary *value =[self.locations objectForKey:loc];
        
        myAnnotation.coordinate = CLLocationCoordinate2DMake(
                                                             [[value objectForKey:@"latitude"] doubleValue],
                                                             [[value objectForKey:@"longitude"] doubleValue]);
        myAnnotation.title = [value objectForKey:@"Title"];
        //myAnnotation.subtitle = [value objectForKey:@"subtitle"];
        
        //NSLog(@"%@",myAnnotation.title);
        [self.mapView addAnnotation:myAnnotation];
        
    }
    

Open in new window

       

You say:
for (NSString *loc in self.locations)

and then:

NSDictionary *value =[self.locations objectForKey:loc];

It looks like an error. Probably, 'loc' is not a NSString object.
0
[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

 

Author Comment

by:Strongs
ID: 38373280
Hi,

Attached is a snapshot of the plist that the dictionary is pulling its data from. This consists of Dictionary objects that contain strings.

If *loc should not be a NSString then is there another NS object that can be used to extract the data?

Thanks.
plist.tiff
0
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 38373435
You set the items as NSDictionary in this plist.
I'd use enumerateKeysAndObjectsUsingBlock:
[[sels locations] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
    NSDictionary *loc = (NSDictionary *)obj
}];
With your code it's probably
for (NSDictionary *loc in [self locations] ) {
// here is the code like:
    myAnnotation.title = [loc objectForKey:@"Title"];
}
0
 

Author Comment

by:Strongs
ID: 38373577
Thanks for the code. Unfortunately, same issue. The leak is evident when the offending view is dismissed with DismissModalViewController and not when it is active. not sure if this will help to track down the issue.

The code used in case I have something wrong:

 //loop through plist to add pins to map
    for (NSDictionary *loc in self.locations) {
            
        [[self locations] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
            
            NSDictionary *loc = (NSDictionary *)obj;
            
            //NSLog(@"loc: %@",loc);
            MKPointAnnotation *myAnnotation=[[MKPointAnnotation alloc]init];
            //NSDictionary *value =[self.locations objectForKey:loc];
            
            myAnnotation.coordinate = CLLocationCoordinate2DMake(
                                                                 [[loc objectForKey:@"latitude"] doubleValue],
                                                                 [[loc objectForKey:@"longitude"] doubleValue]);
            myAnnotation.title = [loc objectForKey:@"Title"];
            //myAnnotation.subtitle = [value objectForKey:@"subtitle"];
            
            //NSLog(@"%@",myAnnotation.title);
            [self.mapView addAnnotation:myAnnotation];
        }];
        
       
        
    }

Open in new window

0
 

Author Comment

by:Strongs
ID: 38373593
Forgot to point out that when using the code above, the shadow on the pins becomes much heavier. Is this due to multiple pins being placed on the map view?
0
 
LVL 33

Accepted Solution

by:
pgnatyuk earned 1500 total points
ID: 38374857
At least the error in the code was fixed.

I don't understand why you write this line:
for (NSDictionary *loc in self.locations)

this is the same as
[[self locations] enumerateKeysAndObjectsUsingBlock

I think, you need only one from them.


And probably this line drives crazy the tool:
MKPointAnnotation *myAnnotation=[[MKPointAnnotation alloc]init];
Try to add
myAnnotation = nil

in the end:

       
 [[self locations] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
            
            NSDictionary *loc = (NSDictionary *)obj;
            
            //NSLog(@"loc: %@",loc);
            MKPointAnnotation *myAnnotation=[[MKPointAnnotation alloc]init];
            //NSDictionary *value =[self.locations objectForKey:loc];
            
            myAnnotation.coordinate = CLLocationCoordinate2DMake(
                                                                 [[loc objectForKey:@"latitude"] doubleValue],
                                                                 [[loc objectForKey:@"longitude"] doubleValue]);
            myAnnotation.title = [loc objectForKey:@"Title"];
            //myAnnotation.subtitle = [value objectForKey:@"subtitle"];
            
            //NSLog(@"%@",myAnnotation.title);
            [self.mapView addAnnotation:myAnnotation];
            myAnnotation = nil;
        }];
   

Open in new window

0
 

Author Comment

by:Strongs
ID: 38375665
Well, this is highly embarrassing! I tested the original code block again uncommenting each line to see where the leak is occurring. Don't now how I missed this first time but here is what I found.

 //loop through plist to add pins to map
    for (NSDictionary *loc in self.locations) {
        
        //NSLog(@"loc: %@",loc);
        MKPointAnnotation *myAnnotation=[[MKPointAnnotation alloc]init];
        NSDictionary *value =[self.locations objectForKey:loc];
        
        myAnnotation.coordinate = CLLocationCoordinate2DMake(
                                                             [[value objectForKey:@"latitude"] doubleValue],
                                                             [[value objectForKey:@"longitude"] doubleValue]);

        myAnnotation.title = [value objectForKey:@"Title"]; // leaks here******
        
        myAnnotation.title = nil; //this line fixes the leaks!!****

        //myAnnotation.subtitle = [value objectForKey:@"subtitle"];
        
//        //NSLog(@"%@",myAnnotation.title);
        [self.mapView addAnnotation:myAnnotation];
        
    }

Open in new window


Must be a retain/release error on the title string? I am not sure why.

Thanks for your help this far. I will use your code above with the amendment above as this is much cleaner and award points accordingly.

Regards,
0
 

Author Closing Comment

by:Strongs
ID: 38378915
Thanks for your help.
0
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 38379395
You are welcome
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When Apple released Swift last year, the aim was to introduce a new programming language for Cocoa and Cocoa Touch that was fast, easy and effective, like the name connotes. Apple succeeded. Swift is designed to couple with Objective-C program…
Short answer to this question: there is no effective WiFi manager in iOS devices as seen in Windows WiFi or Macbook OSx WiFi management, but this article will try and provide some amicable solutions to better suite your needs.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
Suggested Courses

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question