tabBarController memory leak - iphone

In my AppDelegate I initiate a tabBar Controller, to which a bunch of navigationController is added as tabs. I use the following code:
// Init tabBar Controller
tabBarController = [[[UITabBarController alloc] init] retain];
// Init Root Views of navigation controllers
FirstRootViewController* firstViewController = [[[FirstRootViewController alloc] init] autorelease];
SecondRootViewController* secondViewController = [[[SecondRootViewController alloc] init] autorelease];
ThirdRootViewController* thirdViewController = [[[ThirdRootViewController alloc] init] autorelease];
// Init Navigation controllers of tabs
UINavigationController* firstNavController = [[[UINavigationController alloc] initWithRootViewController:firstViewController] autorelease];
UINavigationController* secondNavController = [[[UINavigationController alloc] initWithRootViewController:secondViewController] autorelease];
UINavigationController* thirdNavController = [[[UINavigationController alloc] initWithRootViewController:thirdViewController] autorelease];
firstNavController.navigationBar.barStyle = UIBarStyleBlack;
secondNavController.navigationBar.barStyle = UIBarStyleBlack;
thirdNavController.navigationBar.barStyle = UIBarStyleBlack;
// Create array for tabBarController and add navigation controllers to tabBarController
NSArray *navigationControllers = [NSArray arrayWithObjects:firstNavController, secondNavController, thirdNavController, nil];
tabBarController.viewControllers = navigationControllers;
[window addSubview:tabBarController.view];
And the dealloc function:
- (void)dealloc {
[window release];
[tabBarController release];
[super dealloc]; }
firstNavController are the navigation controllers to be added which are properly released altogether a few lines later (they are created using alloc).
TabBarController is a class variable which has been created using #property (nonatomic, retain) and #synthesize tabBarController. It receives a release command in the dealloc method.
Now instruments tells me that I have two memory leaks on the line with "tabBarController.viewControllers = navigationController".
I have tortured my head, yet I don't see why: From my understanding, navigationControllers should get released automatically and if I send it a release command a few lines later, the app crashes, so I guess I am right.
Any guesses whats wrong?
Thanks a lot!

Firstly, your tabBarController class variable has it's reference count increased twice. Once from the alloc and once from the retain in the first line of your code, yet is only released once in dealloc This is probably where your memory leak is coming from.
Secondly, although you have declared a matching #property(nonatomic, retain) tabBarController (and implemented via #sysnthesize) you are not actually using the property accessors (and its corresponding retain & release behaviour during assignment) To do this you need to use self.tabBarController rather than just tabBarController which will refer to the class variable, not the property.
Try modifying your code to the following to see if this solves your problem
// Init tabBar Controller
UITabBarController* tbc = [[[UITabBarController alloc] init];
self.tabBarController = tbc;
[tbc release];
...
- (void)dealloc {
[window release];
self.tabBarController = nil;
[super dealloc]; }

Related

UINavigationController within a UITabBarController, setting the navigation controller title

In my app I have a UINavigationController within a UITabBarController. Everything is working fine, however I can't set the title for the navigation controller. I have tried several different methods and googled around but there seems to be no solution for this problem.
Any Help would be greatly appreciated.
Thankyou in advance.
Sam
I found the answer in the end, it was:
self.tabBarController.navigationItem.title = #"title";
self.navigationItem.title = #"Your Title"
Works for every case.
For me the following works fine:
Initiate the controllers in appDelegateDidFinishLaunching:Method:
UINavigationController *navContr1;
UINavigationController *navContr2;
UIViewController *viewController1, *viewController2;
viewController1 = [[[FirstViewController alloc] initWithNibName:#"FirstViewController_iPhone" bundle:nil] autorelease];
viewController2 = [[[SecondViewController alloc] initWithNibName:#"SecondViewController_iPhone" bundle:nil] autorelease];
navContr1 = [[[UINavigationController alloc] initWithRootViewController:viewController1] autorelease];
navContr2 = [[[UINavigationController alloc] initWithRootViewController:viewController2] autorelease];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
//self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navContr1, navContr2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
with this done, in your different viewControllers initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil - Method you can change the title with the following line:
self.title = #"Your Title";
Good Luck.
Look at the UIViewController class in the docs. There is a property pointing to the UINavigationItem which then has a property pointing to the title. If the pointer to the navigation item returns nil, you must have not wired the controllers together correctly.
The self.title always sets the tile of the rootViewController object of your ViewController.
If you have your viewController & the rootViewController is UINavigationController, then self.title will set the title of UINavigationController.
Similarly, if you have initialized a UITabViewController with the UIViewController objects, then the self.title will applies on the title corresponding button at index, on UITabBar of UITabViewController.
Hence said that, self.title applies on the object holding the viewController.

UITabBarController Does not shows tabbarItems name

I am creating app based on UTabbarController. I have creates that tab bar programmatically. Everything is running fine except I can not see the tabBatItem title. I have initialized everything properly, but when application launches all I can see is the first tabbar title. but if I select 2nd tabbaritem or so on I can see their names. I don't know whats going wrong here. Here is my code. Please let me know if I made any mistake.
Thanks.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
HomeViewController *viewController1 = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil];
UINavigationController*navController1=[[UINavigationController alloc]initWithRootViewController:viewController1];
navController1.title=#"Home";
[viewController1 release];
TrainerTableViewController *viewController2 = [[TrainerTableViewController alloc] initWithNibName:#"TrainerTableViewController" bundle:nil];
UINavigationController*navController2=[[UINavigationController alloc]initWithRootViewController:viewController2];
navController1.title=#"Trainer";
[viewController2 release];
SettingsTableViewController *viewController8 = [[[SettingsTableViewController alloc] initWithNibName:#"SettingsTableViewController" bundle:nil] autorelease];
UINavigationController*navController8=[[[UINavigationController alloc]initWithRootViewController:viewController8]autorelease];
navController1.title=#"Settings";
AboutUsViewController *viewController9 = [[[AboutUsViewController alloc] initWithNibName:#"AboutUsViewController" bundle:nil] autorelease];
UINavigationController*navController9=[[[UINavigationController alloc]initWithRootViewController:viewController9]autorelease];
navController1.title=#"About Us";
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navController1, navController2,navController8, navController9, nil];
[navController1 release];
[navController2 release];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
You can do this by including the code below inside the .m file of the view controller for each tab bar item. The code also includes how to change the image on the tab bar.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
self.title = #"Apply Now";
self.tabBarItem.image = [UIImage imageNamed:#"tbApplyNow.png"];
}
return self;
}
The best way to solve this problem is to set title of viewController not of navigationController
viewController1.tabBarItem.title = #"CohesiveSelf";
Do this for all tabs.
You're only setting the title for navController1. For each nab controller you create you need to set the title for that one.
Try this:
CHANGE:
navController1.title=#"Trainer";
TO
navController2.title=#"Trainer";
CHANGE:
navController1.title=#"Settings";
TO
navController8.title=#"Settings";
CHANGE:
navController1.title=#"About Us";
TO
navController9.title=#"About Us";
Also not you are not releasing navController8 or 9 which will cause in a memory leak
You are actually setting the title for the NavigationControllers. Also, watch that your code sets the title of navController1 multiple times, rather than setting it for the others.
You can set the titles for your tabBar by setting up tabBarItems for each controller.
You have the option of subclassing, or just including this in the application:didFinishLaunchingWithOptions: method in your AppDelegate.
Here's an example:
UITabBarItem *tbi1 = [navController1 tabBarItem];
[tbi1 setTitle:#"Home"];
UIImage *i1 = [UIImage imageNamed:#"hometabicon.png"];
[tbi1 setImage:i1];
This will set the title of tab1 to 'Home' and will set the tabBar icon to a file named 'hometabicon.png'.
You can repeat the same pattern for each of the other tabs.

Right design pattern for tabbed navigation views?

I've been stuck trying to puzzle this out for a couple days now, and I'll admit I need help.
The root view controller of my application is a tab bar controller. I want to have each tab bar a different navigation controller. These navigation controllers have completely different behavior.
So how do I set this up in terms of classes? Per Apple's documentation, I'm not supposed to subclass UINavigationViewController. So where do I put the code that drives each of these navigation controllers? Does it all get thrown in App Delegate? That would create an impossible mess.
This app should run on iOS 4.0 or later. (Realistically, I can probably require iOS 4.2.)
This is taken from one of my applications. As you say, you are not supposed to subclass UINavigationController, instead you use them as they are and you add viewcontroller on the UINavigationController's. Then after setting the root viewcontroller in each UINavigationController, you add the UINavigationController to the UITabBarController (phew!).
So each tab will "point" to a UINavigationController which has a regular viewcontroller as root viewcontroller, and it is the root viewcontroller (the one you add) that will be shown when a tab is pressed with a (optional) navigationbar at top.
UITabBarController *tvc = [[UITabBarController alloc] init];
self.tabBarController = tvc;
[tvc release];
// Instantiates three view-controllers which will be attached to the tabbar.
// Each view-controller is attached as rootviewcontroller in a navigationcontroller.
MainScreenViewController *vc1 = [[MainScreenViewController alloc] init];
PracticalMainViewController *vc2 = [[PracticalMainViewController alloc] init];
ExerciseViewController *vc3 = [[ExerciseViewController alloc] init];
UINavigationController *nvc1 = [[UINavigationController alloc] initWithRootViewController:vc1];
UINavigationController *nvc2 = [[UINavigationController alloc] initWithRootViewController:vc2];
UINavigationController *nvc3 = [[UINavigationController alloc] initWithRootViewController:vc3];
[vc1 release];
[vc2 release];
[vc3 release];
nvc1.navigationBar.barStyle = UIBarStyleBlack;
nvc2.navigationBar.barStyle = UIBarStyleBlack;
nvc3.navigationBar.barStyle = UIBarStyleBlack;
NSArray *controllers = [[NSArray alloc] initWithObjects:nvc1, nvc2, nvc3, nil];
[nvc1 release];
[nvc2 release];
[nvc3 release];
self.tabBarController.viewControllers = controllers;
[controllers release];
This is how I go from one viewcontroller to another one (this is done by tapping a cell in a tableview but as you see the pushViewController method can be used wherever you want).
(this is taken from another part of the app)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.detailedAnswerViewController == nil) {
TestAnsweredViewController *vc = [[TestAnsweredViewController alloc] init];
self.detailedAnswerViewController = vc;
[vc release];
}
[self.navigationController pushViewController:self.detailedAnswerViewController animated:YES];
}
The self.navigationcontroller property is of course set on each viewcontroller which are pushed on the UINavigationController hierachy.

Using self dot notation doesn't call dealloc

The dealloc method of my view controller class is not called when popped after being pushed with the following code:
self.playerViewController = [[VideoPlayerViewController alloc] init];
[self.playerViewController set_video:video];
[self.navigationController pushViewController:self.playerViewController animated:YES];
[self.playerViewController release];
However if I change the push code to the following, then my dealloc is called appropriately after the view controller is popped:
playerViewController = [[VideoPlayerViewController alloc] init];
[playerViewController set_video:video];
[self.navigationController pushViewController:playerViewController animated:YES];
[playerViewController release];
I thought I understood the use of dot notation/self, but obviously not. Can anyone explain the problem here?
Here is the property:
#property (nonatomic, retain) VideoPlayerViewController *playerViewController;
and here is the synthesize:
#synthesize playerViewController;
You are retaining twice.
self.playerViewController = [[VideoPlayerViewController alloc] init];
^ retain + 1 ^^^^^ retain + 1
But you only release one time.
To fix your memory management issue you could change the code to something like this:
self.playerViewController = [[[VideoPlayerViewController alloc] init] autorelease];
And many people say [self.foo release] is bad style. You should consider to replace it with [foo release]

Can't get Secondary UITableViewController to display inside a UITabBarController

I've programmatically created a UITabBarController that is loaded in my App Delegate like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
tabBarController = [[UITabBarController alloc] init];
myTableViewController = [[MyTableViewController alloc] init];
UINavigationController *tableNavController = [[[UINavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
myTableViewController.title = #"Tab 1";
[myTableViewController release];
mySecondTableViewController = [[MySecondTableViewController alloc] init];
UINavigationController *table2NavController = [[[UINavigationController alloc] initWithRootViewController:mySecondTableViewController] autorelease];
mySecondTableViewController.title = #"Tab 2";
[mySecondTableViewController release];
tabBarController.viewControllers = [NSArray arrayWithObjects:tableNavController, table2NavController, nil];
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
Now the issue I have is that I can get into the views no problem, but when I try and click onto any item in the Table View, I can't get a secondary table view to appear in any tab. The tabs work absolutely fine, just the secondary views. I'm using the code below in my myTableViewController to run when selecting a specific row (the code reaches the HELP line, and crashes)...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
// this gets the correct view controller from a list of controllers
SecondaryViewController *svc = [self.controllers objectAtIndex:row];
/*** HELP NEEDED WITH THIS LINE ***/
[self.navigationController pushViewController:svc animated:YES];
}
Simply put, I'm trying to switch views to the new view controller whilst keeping the tabs available and using the navigation to go back and forth (like in the iTunes App).
Simply put, I was creating the controller array, self.controllers, and adding objects, and then releasing the objects.
If you do not release the object until the array is released, it appears to work no problem.
You've not included in your question how you initialize the self.controllers array.
I suspect this array is not filled with initialized SecondaryViewController objects.
EDIT (Added Code example that works for me):
the .h file:
#interface FirstLevelViewController : UITableViewController {
NSArray *controllers;
}
#property (nonatomic, retain) NSArray *controllers;
#end
and the .m file:
#implementation FirstLevelViewController
#synthesize controllers;
- (void)viewDidLoad {
self.title = #"First Level";
NSMutableArray *array = [[NSMutableArray alloc] init];
// Disclosure Button
DisclosureButtonController *disclosureButtonController =
[[DisclosureButtonController alloc]
initWithStyle:UITableViewStylePlain];
disclosureButtonController.title = #"Disclosure Buttons";
disclosureButtonController.rowImage = [UIImage
imageNamed:#"disclosureButtonControllerIcon.png"];
[array addObject:disclosureButtonController];
[disclosureButtonController release];
// deleted further adds to array ...
self.controllers = array;
[array release];
[super viewDidLoad];
}