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
Related
I am trying to create a back button to return to the main menu of my app, what is happening now, is, once I press the back button, it shows the main menu, but then the app crashes out a second later.
The code I use for back button is;
- (void)backButtonPressed:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
From the AppDelegate.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[[MenuViewController alloc] initWithNibName:#"MenuViewController_iPhone" bundle:nil] autorelease];
} else {
self.viewController = [[[MenuViewController alloc] initWithNibName:#"MenuViewController_iPad" bundle:nil] autorelease];
}
navigationController = [[myNavigationViewController alloc] initWithRootViewController:self.viewController];
navigationController.navigationBarHidden = YES;
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
I cannot see where I am going wrong? It seems to call the right screen, yet crashes straight after?
EDIT - Here is MenuViewController.m file;
#import "MenuViewController.h"
#import "MagicAppDelegate.h"
#import "MagicViewController.h"
#interface MenuViewController ()
#end
#implementation MenuViewController
- (void)viewDidLoad
{
self.view.frame = [[UIScreen mainScreen] bounds];
[super viewDidLoad];
// [self initLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)onStart:(id)sender
{
MagicViewController* viewController;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
viewController = [[MagicViewController alloc] initWithNibName:#"MagicViewController_iPhone" bundle:[NSBundle mainBundle]];
else
viewController = [[MagicViewController alloc] initWithNibName:#"MagicViewController_iPad" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
- (void)dealloc {
[super dealloc];
}
#end
Please use below code,do u want go mainmenuview controller.
[self.navigationController popToRootViewControllerAnimated:YES];
Actually, I don't understand your code: In the statement navigationController = [[myNavigationViewController alloc] initWithRootViewController:self.viewController]; you are sending an alloc to something that seems to be the instance of class UINavigationController, but alloc is a class method. I therefore assume myNavigationViewController is a subclass of UINavigationController (but then is should start with a capital letter).
The new instance returned is then assigned directly, i.e. without using a setter method, to variable navigationController. It is therefore not retained. If your statement returns an autorelease object, it will thus be released as soon as the program returns to the main event loop.
Try thus to use thus a setter method, i.e. self.navigationController = [[myNavigationViewController alloc] initWithRootViewController:self.viewController];
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!");
}
So I have to admit, that I had this code working perfectly up until a day or so ago when I added a new view, so I'm rather frustrated at the moment.
The setup:
I have a storyboarded app that contains a tabbar. In the AppDelegate, I have the following for attaching the CoreData
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UINavigationController *navigationController = [[tabBarController viewControllers] objectAtIndex:0];
GamesViewController *controller = [[navigationController viewControllers] objectAtIndex:0];
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
Also in the AppDelegate, I had this method that would set the standard tab background to an image of my choosing:
- (void)customizeInterface {
UIImage* tabBarBackground = [UIImage imageNamed:#"tab_background"];
[[UITabBar appearance] setBackgroundImage:tabBarBackground];
}
So this all worked fine until I added another login view that precedes my tabs. I had to change what the CoreData was initially being set too (from my tabs to my login/initializing view). Below is the new setup of how the storyboard looks.
Now when the app loads up... the background image appears initially as before, but only on the first tab. Once I click off if it, it switches to the default gradient color again. If I go back to the first / initial tab, the background does not-reapply itself, it stays as the colored gradient.
Here is the amended applicationDidFinishLaunching code to go along with it:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//instantiate local context
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// Handle the error.
NSLog(#"Error: Context is null");
}
LoginViewController *rootViewController = [LoginViewController alloc];
rootViewController.managedObjectContext = context;
return YES;
}
So then what I tried to do, is go into the viewDidLoad in the first VC that my tabbar loads up (GameViewController) and tried adding this to fix the problem:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tabBarController.tabBar setBackgroundImage:[UIImage imageNamed:#"dock_background"]];
}
That didn't work, so I also tried using the same original code that I had in my AppDelegate and that also didn't work:
- (void)viewDidLoad {
[super viewDidLoad];
UIImage* tabBarBackground = [UIImage imageNamed:#"tab_background"];
[[UITabBar appearance] setBackgroundImage:tabBarBackground];
}
So... I'm sort of stuck. I've got to be doing (or not doing) something so obvious... Anyone out there have any tips / pointers?
Thanks a ton
- Drew
Delegate.h file
#interface AppDelegate : UIResponder
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UIImageView *imgV;
#property (strong, nonatomic) UIViewController *viewController;
#property (strong, nonatomic) UITabBarController *tabBarController;
#end
Delegate.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[DeskboardVctr alloc] initWithNibName:#"DeskboardVctr" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.delegate=self;
self.imgV=[[UIImageView alloc] init];
self.imgV.frame=CGRectMake(0, 0, 1024, 49);
[[self.tabBarController tabBar] insertSubview:self.imgV atIndex:1];
self.tabBarController.delegate=self;
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Tabbar Delegate Methods
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
NSUInteger index=[[tabBarController viewControllers] indexOfObject:viewController];
switch (index) {
case 0:
self.imgV.image=[UIImage imageNamed:#"t1.png"];
break;
case 1:
self.imgV.image=[UIImage imageNamed:#"t2.png"];
break;
case 2:
self.imgV.image=[UIImage imageNamed:#"t3.png"];
break;
case 3:
self.imgV.image=[UIImage imageNamed:#"t4.png"];
break;
case 4:
self.imgV.image=[UIImage imageNamed:#"t5.png"];
break;
default:
break;
}
return YES;
}
Hope you may help this
thanks
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
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;
}