PushViewController: Is this a memory leak? - iphone

I'm developing an iOS 4 with latest SDK and XCode 4.2 (I'm not using ARC).
I'm developing a Navigation Controller programmatically, and I have a question.
This is AppDelegate.h
#import <UIKit/UIKit.h>
#class ViewController;
#class SecondViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UINavigationController* navController;
ViewController* viewController;
SecondViewController* secondViewController;
}
#property (strong, nonatomic) UIWindow *window;
- (void) showSecondViewController;
#end
And this is AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#import "SecondViewController.h"
#implementation AppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
viewController.title = #"Menu";
navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.navigationBar.tintColor = [UIColor blackColor];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
- (void) dealloc
{
[_window release];
[viewController release];
[navController release];
[secondViewController release];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
...
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
...
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
...
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
...
}
- (void)applicationWillTerminate:(UIApplication *)application
{
...
}
- (void) showSecondViewController
{
secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.title = #"Second";
[navController pushViewController:secondViewController animated:YES];
}
My question is about the last method, -(void)showSecondViewController;
May I add this line at the end?
[secondViewController release]
I've profiled the application, and I haven't see any memory leaks. But I have to ask it here, because I'm not sure.

You will get a memory leak if you call showSecondViewController method again.
You should release the secondViewController in your showSecondViewController method.
- (void) showSecondViewController
{
secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.title = #"Second";
[navController pushViewController:secondViewController animated:YES];
[secondViewController release]
}
It will automatically be retained by navController when you do pushViewController:secondViewController

Related

How to access method linked to UIBarButton on NavigationController

II wanted to add a UIBarButton to my UINavigationController. I did that with the help of following code,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIViewController *rootController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:rootController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *addInfoButton = [[UIBarButtonItem alloc] initWithTitle:#"Add Info" style:UIBarButtonItemStylePlain target:self action:#selector(addCustomerInfo)];
self.navigationItem.rightBarButtonItem = addInfoButton;
}
-(void) addCustomerInfo
{
AddInfoViewController *addVC = [[AddInfoViewController alloc] initWithNibName:#"AddInfoViewController" bundle:nil];
[addVC setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentModalViewController:addVC animated:YES];
}
Should I declare "-(void) addCustomerInfo" in .h file? I already tried that but no luck.
The code still throws the exeption,
2012-08-06 04:16:22.200 TableView[5698:f803] -[RootViewController addCustomerInfo]: unrecognized selector sent to instance 0x6c662b0
2012-08-06 04:16:22.202 TableView[5698:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RootViewController addCustomerInfo]: unrecognized selector sent to instance 0x6c662b0'
The code for your class is correct. You need to change your App Delegate
I suggest creating a property in your App Delegate to store your navigation controller -#property (strong, nonatomic) UINavigationController *navController; - Don't forget to synthesize it.
Then, when you create your Navigation controller, set it to your property - self.navController = [[UINavigationController alloc] init];
This will guarantee your NavigationController is properly retained and that it can be accessed correctly by other classes in your application.
Below some sample code that might make it clearer:
First the AppDelegate header file:
//AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UINavigationController *navController;
}
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UINavigationController *navController;
#end
And the implementation file:
// AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize navController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.navController = [[UINavigationController alloc] init];
UIViewController *myVC= [[myVC alloc] init];
[self.navController pushViewController:myVC animated:NO];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
Check out this tutorial:
http://www.innovatelabs.in/2010/03/implementing-uibarbuttonitem/
I'm not so fluent with iOS, but usually when you use a selector, your add : to it #selector(addCustomInfo:)
and then the function would look like this:
-(void) addCustomInfo:(UIBarButtonItem *)myButton {
NSLog(#"YOU CLICKED ME!");
}

Two table view in one view controller - pushing any view controller is not working

I have two table view in one view controller.
They works great! But they are not pushing to any vc.
Under -(void) viewDidLoad method in my main view controller:
horizontalViewController = [[HorizontalViewController alloc] init];
verticalViewController = [[VerticalViewController alloc] init];
[horizontalTableView setDataSource:horizontalViewController];
[verticalTableView setDataSource:verticalViewController];
[horizontalTableView setDelegate:horizontalViewController];
[verticalTableView setDelegate:verticalViewController];
horizontalViewController.view = horizontalViewController.tableView;
verticalViewController.view = verticalViewController.tableView;
What can I do?
Thanks.
refer a following code. If you want use a pushViewController method.
You must be have a NavigationViewController.
so, your structure is a little complex. one ViewController has number of Two TableViewController. one ViewController is not have NavigationController. NavigaitonViewController necessarily belong to the app when it runs because it should be configured.
TwoTableViewsAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UINavigationController *naviController = [[[UINavigationController alloc] initWithRootViewController:viewController] autorelease];
[window setRootViewController:naviController];
[window makeKeyAndVisible];
return YES;
}
TwoTableViewsViewController.m
- (void)viewDidLoad {
if (firstController == nil) {
firstController = [[FirstTVContoller alloc] init];
}
if (secondController == nil) {
secondController = [[SecondTVController alloc] init];
}
[firstTable setDataSource:firstController];
[secondTable setDataSource:secondController];
[firstTable setDelegate:firstController];
[secondTable setDelegate:secondController];
firstController.view = firstController.tableView;
secondController.view = secondController.tableView;
firstController.rootViewController = self;
secondController.rootViewController = self;
[super viewDidLoad];
}
FirstTVContoller.h , SecondTVController.h
#import <Foundation/Foundation.h>
#interface FirstTVContoller : UITableViewController <UITableViewDataSource, UITableViewDelegate>{
NSMutableArray *items;
}
#property (nonatomic, retain) UIViewController *rootViewController;
#end
FirstTVContoller.m , SecondTVController.m
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
VerticalDetailViewController *verticalDetailViewController = [[VerticalDetailViewController alloc] initWithNibName:#"VerticalDetailViewController" bundle:nil];
[[self.rootViewController navigationController] pushViewController:verticalDetailViewController animated:YES];
}

Go from UITableView cell to a Detail view

I have searched a lot about this topic and I can't get this code work. When I execute it, it only shows my test NSLog but the code to go from one view to another doesn't do anything. Here you have the following code:
//FirstViewController.h
#import <UIKit/UIKit.h>
#import "StationDetailsViewController.h"
#interface FirstViewController : UIViewController{
NSArray *ListaEstaciones;
NSArray *ListaID;
}
#property (nonatomic, retain) NSArray *ListaEstaciones;
#property (nonatomic, retain) NSArray *ListaID;
#end
//FirstViewController.m
#import "FirstViewController.h"
#import "StationDetailsViewController.h"
#implementation FirstViewController
#synthesize ListaEstaciones;
#synthesize ListaID;
//...
- (void)tableView: (UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"Pushing...");
StationDetailsViewController *controller = [[StationDetailsViewController alloc] initWithNibName:#"StationDetailsViewController" bundle:nil];
[[self navigationController] pushViewController:controller animated:YES];
[controller release], controller = nil;
}
#end
I have tried lots of tutorials and my book but I don't know what is wrong. Thanks a lot, guys.
EDIT: Reading your answers I found that the error is on AppDelegate.m where rootViewController is defined.
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
UIViewController *viewController3 = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, viewController3, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
I don't know what to edit here to make this:
[[self navigationController] pushViewController:controller animated:YES];
work properly.
i think the problem is in [self navigationController] .. put a break point on this line of code and probaly you will find its value = nil cuz of that you are not having your detail controller .. you could solve this like that UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:yourMainViewControllerInstance];
This The appDelegate Code :
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
UIViewController *firstViewController = [[[FirstViewController alloc] initWithNibName:#"FBConFirstViewController" bundle:nil] autorelease];
UIViewController *secondViewController = [[[SecondViewController alloc] initWithNibName:#"FBConSecondViewController" bundle:nil] autorelease];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:firstViewController]autorelease];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:nav, secondViewController, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
I guess there is some problem either with datasource and delegate settings or your navigation controller.
Check this tutorial UITableView Tutorial
This might be helpful to you.
Enjoy Coding :)

app delegate leak problem

When I do an analyze in xcode, I get this memory leak on the navController in my appdelegate.m.
The app runs fine, but I just can't get this warning to go away. Can anyone help? Is this ok?
Really appreciate anyone help.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
// create window and set up view controller
[window addSubview:navController.view];
[window makeKeyAndVisible];
navController.topViewController.title = SHKLocalizedString(#"Quick Lomo Pro");
navController.navigationBar.tintColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];
navController.navigationBar.translucent = NO;
[navController setToolbarHidden:YES];
}
You are never releasing the "UINavigationController" after you call the init.
You should store a pointer to the navigation controller and release it in you appdelegate dealloc method.
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UINavigationController *navController;
}
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
navController = [[UINavigationController alloc] init];
...
}
-(void) dealloc {
[navController release];
[super dealloc];
}
#end

Setting UINavigationController, old code?

I have been looking back at some old code from when I first started learning Objective-c and I have a quick question:
// THIS IS MY OLD CODE
#implementation syntax_UINavAppDelegate
#synthesize window;
#synthesize navController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITableViewController *rootController = [[UITableViewController alloc] init];
navController = [[UINavigationController alloc] initWithRootViewController:rootController];
[window addSubview:[[self navController] view]];
[window makeKeyAndVisible];
return YES;
}
my current understanding is that in the above code there are two issues, firstly I am acessing the property navController directly (I should be using the setter) and secondly do I have a memory leak with [UINavigationController alloc]? My gut feeling is that its not a leak as it will get released when I call [navController release]; in dealloc, BUT that its just messey and a bad way to do things. Here is my (now I know a little more) rework of the same code.
// NEW CODE
#implementation syntax_UINavAppDelegate
#synthesize window;
#synthesize navController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITableViewController *rootController = [[UITableViewController alloc] init];
UINavigationController *tempController = [[UINavigationController alloc] initWithRootViewController:rootController];
[self setNavController:tempController];
[rootController release];
[tempController release];
[window addSubview:[[self navController] view]];
[window makeKeyAndVisible];
return YES;
}
just curious ...
Gary
Yep, your second code is definitely better than the first. However, I would change a few things. Skip the tempcontroller, instead assign it directly to navController using dot notation. Make sure you call [navController release] in dealloc though.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITableViewController *rootController = [[UITableViewController alloc] init];
[self.navController = [[[UINavigationController alloc]
initWithRootViewController:rootController] autorelease];
[rootController release];
[window addSubview:self.navController.view];
[window makeKeyAndVisible];
return YES;
}