2
votes

in the very good book "Beginning iPhone Development" (Apress), in the Chapter 9, they explain how to build an application with a navigation controller and hierarchical table views.
If you launch the application with Instrument/Activity monitor, the application working well but with a big problem : each time you drill down from table views into child tables, it takes 1Mo of memory more! and this memory is never released and of course, at the end the application crash. For me the problem come from the following method of "RootViewController.h":
(the original source code is "09 Nav" of the this ZIP file )

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger row = [indexPath row];
    SecondLevelViewController *nextController = [self.controllers objectAtIndex:row];

    NavAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    [delegate.navController pushViewController:nextController animated:YES];

}

in this method "nextcontroller" is never released. in order to use the command [nextController release]; I have made the following modification:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger row = [indexPath row];
    SecondLevelViewController *nextController = [[SecondLevelViewController alloc] init ];
    nextController = [self.controllers objectAtIndex:row];
    NavAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    [delegate.navController pushViewController:nextController animated:YES];
    [nextController release];
}

Now, if you run the application, the memory is well released! But if you try to drill down in a child table where you have already "visited", the application crash.

How can we release the memory properly?
Thank you in advance.

3

3 Answers

1
votes

if you check the source code using the Clang checker (http://clang.llvm.org/StaticAnalysis.html) you will see that there are 3 leaks:

1) PresidentDetailController.m, the object NSIndexPath *newPath (line 75) is never released 2) PresidentDetailController.m, the object UITextField *textField (line 166) is never released 3) PresidentsViewController.m, the object PresidentDetailController *childController (line 86) is never released

The one you suggest is not a leak; your changes to the source code are the reason for the application crashing. Using the Clang checker is very easy, take a look at

http://clang.llvm.org/StaticAnalysisUsage.html#BasicUsage

Kind regards

1
votes

I didn't know the tools "Clang Checker". Thank you, for the time you take to test it. "Clang Checker" seem's to be very powerfull, I'll try it.

I totally agree with you RootViewController:"nextController" is not a leak but is a memory -eater. If you run the application with Instrument/Activity monitor, at the beginning the application takes 7 Mo and each time you go in a child table, it takes 1 Mo of memory more:

  • after 10 times, the application takes 17Mo,
  • after 20 times, the application takes 27 Mo

and so at the end the application crash (if I remember well, an application cannot takes more than 40Mo) and this application doesn't follow the Apple rules in term of memory management.

With my modification, when you go in a child table, it takes one 1Mo of memory, but when you come back to the "root" table, the 1Mo of memory is released. You can go in another child table, coming back, the memory is released. the "only" problem is if you go again in a child table you already visited, the application crash. So, I'm looking for a solution to force the application to release the memory after visiting a child table.

In order to check, with the Instrument/Activity monitor,I have follow the memory used by the Apple Settings application (hierarchical table view application too).When you go in a child table, it takes 1 Mo of memory, but when you come back, the memory is released.

0
votes

The controller is not being released because self.controllers retains it (collections such as NSArray retain objects placed into them). In the second block of code, you're creating a completely independent object, immediately leaking it, and then over-releasing the controller you pull out of self.controllers (which leads to your crash).

It looks like this code intends to hold onto its controllers for the life of the program, so that's not wrong per se. The fact that you're growing in memory suggests that you're creating new objects. I would look for calls to +alloc, +copy or -retain that do not have a corresponding call to +autorelease or +release. In Instruments, use the ObjectAllocation and Leaks instruments to identify the specific memory that is being over-retained and the point at which is created. The creation point doesn't tell you exactly where the error is, but generally it's a good hint.

To learn the drill-down pattern that you're implementing here, you should study the SimpleDrillDown sample code.

And of course, all Cocoa students should commit the Memory Management Rules to heart. They are not complicated, but they are absolutely necessary to understand. I've written a summary of them if it helps.