This code is leaking and I cannot figure our why :-(

Discussion in 'iOS Programming' started by MACloop, May 11, 2010.

  1. MACloop macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #1
    If I remove the table, and only navigate from one view to another, everything is fine. But if I add the table and the in the leaks-instruments click on the back btn at that very moment when the leak-instrument is analyzing, I get a growing leak. I get some small leaks QuartzCore mem_alloc. They are initially 8 Bytes each. Next time the leak appears they are 16 etc. Worse is a [NSCFArray copyWithZone:] leak which initially is 128 Bytes. I have been seaking for this leak for days now and I do not understand what the problem is. My whole app is navigating with tables and I assume (but do not actually have a clue) that my leaks are because of those tables... Any ideas?
    MACloop

    Code:
    @implementation StartViewController
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    	if (self = [super initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil]) { 
    		
    		UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
    		[infoButton setImage:[UIImage imageNamed:@"logo.png"] forState:UIControlStateNormal];
    		[infoButton addTarget:self action:@selector(openInfo:) forControlEvents:UIControlEventTouchUpInside];
    		infoButton.showsTouchWhenHighlighted =  NO;
    		infoButton.frame = CGRectMake(0, 0, 65, 50);
    		UIBarButtonItem *itemForBar = [[UIBarButtonItem alloc]initWithCustomView:infoButton];
    		
    		self.navigationItem.rightBarButtonItem = itemForBar;
    		[itemForBar release];
    	}
        return self;
    }
    
    
    - (void) openInfo:(id)sender {
    	InfoViewController *infoView = [[InfoViewController alloc] initWithNibName:@"InfoViewController" bundle:nil];
    	[self.navigationController pushViewController:infoView animated:YES];
    	[infoView release];
    }
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    	self.tableView.scrollEnabled = NO;
    }
    
    #pragma mark Table view methods
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 1;
    }
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return 5;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)t cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        
        static NSString *CellIdentifier = @"Cell";
    	
        StartTableViewCell *cell = (StartTableViewCell *)[t dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[StartTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        }
    	cell.backgroundColor = [UIColor lightGrayColor];
    	UIView *bg = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 60)];
    	bg.backgroundColor = selectedBackground;
    	[cell setSelectedBackgroundView:bg];
    	[bg release];
    
    	switch ([indexPath row]) {
    		case 0:
    			[cell setHeadline:@"Test0"];
    			[cell setTextline:@"Test0"];
    			[cell setTheBackground:@"Test0.png"];
    			break;
    		case 1:
    			[cell setHeadline:@"Test1"];
    			[cell setTextline:@"Test1"];
    			[cell setTheBackground:@"Test1.png"];
    			break;
    		case 2:
    			[cell setHeadline:@"Test2"];
    			[cell setTextline:@"Test2"];
    			[cell setTheBackground:@"Test2.png"];
    			break;
    		case 3:
    			[cell setHeadline:@"Test3"];
    			[cell setTextline:@"Test3"];
    			[cell setTheBackground:@"Test3.png"];
    			break;
    		case 4:
    			[cell setHeadline:@"Test4"];
    			[cell setTextline:@"Test4"];
    			[cell setTheBackground:@"Test4.png"];
    			break;
    		default:
    			break;
    	}
        return cell;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    	return 61;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        
    	switch ([indexPath row]) {
    		case 0:
    			a = [[aObjectViewController alloc] initWithNibName:@"aObjectViewController" bundle:nil];
    			[self.navigationController pushViewController:a animated:YES];
    			[a release];
    			break;
    		case 1:
    			b = [[bObjectViewController alloc] initWithNibName:@"bObjectViewController" bundle:nil];
    			[self.navigationController pushViewController:b animated:YES];
    			[b release];
    			break;
    		case 2:
    			c = [[cObjectViewController alloc] initWithNibName:@"cObjectViewController" bundle:nil];
    			[self.navigationController pushViewController:c animated:YES];
    			[c release];
    			break;
    		case 3:
    			d = [[cObjectViewController alloc] initWithNibName:@"dObjectViewController" bundle:nil];
    			[self.navigationController pushViewController:d animated:YES];
    			[d release];
    			break;
    		case 4:
    			e = [[eObjectViewController alloc] initWithNibName:@"cObjectViewController" bundle:nil];
    			[self.navigationController pushViewController:e animated:YES];
    			[e release];
    			break;
    		default:
    			break;
    	}
    }
    
    - (void)didReceiveMemoryWarning {
    	// Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
    }
    
    - (void)viewDidUnload {
    	// Release any retained subviews of the main view.
    	// e.g. self.myOutlet = nil;
    }
    
    - (void)dealloc {
        [super dealloc];
    }
    @end
    
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    What line in your code is indicated by the leaks tool as the line where the leaked object was created?
     
  3. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #3
    There is no line indicated - but after 100 of tests I commented this code out and running the app then gave no leak indication... So, I do not know if this is the code with a leak :-(

    One thing I thought about:
    I get data via an URL and parses the data into an array. This is all done from the AppDelegate. In the AppDelegate is this array with the data. From my viewController using this data I (in viewDidLoad) call
    Code:
    for(Object *o in [(AppDelegate*)[[UIApplication sharedApplication] delegate] objectList]){
    		[self.mutableList addObject:o];
    	}
    I retain mutableList i the .h-file and release it in the dealloc. Is this wrong?

    Thanks in sdvance!
    MACloop
     
  4. TiberiusXavier macrumors member

    Joined:
    Apr 18, 2010
    Location:
    Chicago
    #4
    Can you explain this better? Did you make mutableList a property? If so, what is the full declaration for it?

    You may need to just add a release message in your dealloc:
    Code:
    - (void)dealloc {
        [super dealloc];
        [mutableList release];
    }
    
     
  5. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #5
    Yeah there is. When you select a leaked block in the list of leaked blocks you can see the stack trace where the block was allocated. Without looking at that stack trace you can't figure out a leak.
     
  6. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #6
    Yes, you are right - but this stack trace does not give me any indication on what part of my code that is causing the leak. It only says that Foundation framework and a NSCFArray with 128 bytes is leaking... I have put some imgages into another thread here but I post the same images here aswell. Perhaps it indicates something to you?
    Thanks a lot in advance!
    MACloop
     

    Attached Files:

  7. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #7
    So, I have gone back to a previous version and step by step done the changes in order to reach the current version. The leak appears when I use map.showsUserLocation = YES; The background is, that I am using a navigationViewcontroller and to avoid a common bug in the mapkit I implement the mapview as follows:

    Code:
    .h
    IBOutlet MKMapView *map;
    [COLOR="Green"]//defined in IB[/COLOR] 
    
    .m
    MKCoordinateRegion region;
    	MKCoordinateSpan span;
    	span.latitudeDelta=0.015;
    	span.longitudeDelta=0.015;
    	map.frame = [[UIScreen mainScreen] bounds];
    	map.userLocation.title = @"Sie sind hier!";
    	region.span=span;
    	region.center=some value here;[COLOR="Green"]//dummy[/COLOR]
    	[map setRegion:region animated:TRUE];
    	[map regionThatFits:region];
    	[self.view addSubview:map];
    	[map setHidden:YES];
    [COLOR="Green"]//the map shows when the user clicks a segmentedControl - default is a tableView.[/COLOR]
    If I release and retain the map as I did first, the app crashes when the map is not "ready" loaded at the moment when I use the back button. This blue-dod problem is known as far as I understand... What can I do?

    MACloop
     
  8. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
  9. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #9
    Yes, that is the stack trace. The nature of UIKit is there are a lot of container objects. So if you allocate an NSArray and add 100 strings to it and leak the array you will see all of those strings as leaks also. Fix the leak of the array and all the leaked strings will be fixed also.

    If MKMapView allocates objects that are leaked in code that you call then your code will be visible in one of the stack traces of one of the leaks. However, if the MKMapView uses a timer or responds to a touch, and then allocates a block that it leaks then your code won't be in the stack trace. This is more difficult to figure out.

    If the problem is in the map view then you can use the info in that link to fix it, work around it, or you can choose to ignore it. Simplest might be to only ever create one MKMapView. Don't create it in your nib. Create it in code. Retain it and never release it. You'll need to addSubview it to the view hierarchy where you want it to go.

    In the normal use of your app does the app run out of memory? Releasing an app that has known leaks in it isn't a great choice, and wouldn't be my first choice, but it is a possibility if the app doesn't crash, or at least not much.
     
  10. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #10
    Thanks alot for you very detailed comment! Well, regarding the crash or out-of-memory issue, this has not happend when running the app normally on the device. It has happend though, when the app was running through the instruments-leaks. I do not really understand how it would be possible to only create my mapview once. It is in a navigationcontroller and such a controller "creates" a view everytime the user enters the view. Could you give me an example on how to do this? Or an advice? Thanks very much in advance!
    MACloop
     
  11. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #11
    I thought that it might be a good (?) idea to create the maps needed in the app, in the appDelegate. If I do so and then point to this map everytime I use/create a view in my navigation controller. The problem is only that the mapView does not work as I would like it to. I have created the mapview in the app delegate and I also have set the appDelegate to be a mapviewdelegate. I have created a method in app delegate creating a list with the annotations and I am adding those annotations. So far so good. The problem is that the
    -
    Code:
     (MKAnnotationView *) mapView: (MKMapView *) mapView viewForAnnotation: (id<MKAnnotation>) annotation{
    does not seem to be called and the pin-img:s I have defined are not displayed on the map. Also, the buttons in the calloutviews are not displayed...Only red standard pins are used... Is this the right way of doing this? In my viewcontroller I call:
    Code:
    self.map = (MKMapView*)[(AppDelegate*)[[UIApplication sharedApplication] delegate] map];
    in order to point to the map created in the appDelegate...

    Does anyone have any better solutions on this or tips on how to solve it properly. Acctually it seems like the app only leaks once when creating the map in the appDelegate...
    Thanks in advance!
    MACloop
     
  12. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #12
    If the leak only happens when the mapview is created then you should be in good shape. I would build the mapview in code in the view controller. Assign it to a file scope static variable, aka a global variabel, in the view controller. Make sure it's retained and never release it. Do this in viewDidLoad. Something like

    Code:
    if (sMapView == nil)
    {
    sMapView = ...
    }
    // Here addSubview the mapview to the view controller's view.
    
    I don't think there needs to be any other code to manage the mapview lifespan. Possibly you could removeFromSuperview in your view controller's dealloc method but I'm not certain.
     
  13. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #13
    Hello and thanks for your answer!
    The leak does not appear when the mapview is created, but only when I set the user position to be displayed. If I set it = NO, there is no leak. I suppose that it might be a leak in the mapview framework, in the process where the userposition bluedot is created...? In my app, using a navigation controller, this is becomming very obvious because the mapviews are created everytime the view is displayed. I will try your advice out ... but if I do not release the mapview in the dealloc method, where should I release it? I have alot of mapviews in my app...
    Thanks in advance!
    MACloop
     
  14. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #14
    Cool - your advice seem to solve my problem! The leak seems to be gone :)

    Thanks alot!
    MACloop
     

Share This Page