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;
}
Related
There is a 100% of memory leak shows by instrument at self.window.rootViewController= navigationController;. Application uses ARC.
UINavigationController,UIViewController and window are all properties have attribute strong.
How can i fix this leak.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
txnObserver = [[InAppPurchaseObserver alloc] init];
txnObserver.delegate = self.viewController;
[[SKPaymentQueue defaultQueue] addTransactionObserver:txnObserver];
navigationController = [[UINavigationController alloc]initWithRootViewController:viewController];
**self.window.rootViewController= navigationController;**
[self.window makeKeyAndVisible];
return YES;
}
Same code did not show any leak in iOS 6 but it shows leak in iOS 7.
Updated question on 2013/10/10 with details.
You can change your didFinishLaunchingWithOptions by this following code without #property of viewController :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
with #property (nonatomic, strong) ViewController *viewController; :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
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];
This may be a stupid question but I programmatically added a UINavigationController to my app. If possible, I wanted to just add it to the top of all my windows except for the very first .xib. Maybe even just hide it on my first .xib. Is it possible to even do that? I think of my first .xib file that opens up to the rest of my app like a cover page and I rather that blue bar not show up at the top of that. I wish I could show you pictures but don't have enough reps yet. Thanks!
Below is the code I believe helps me to provide each page of app with the back bar:
#import "McCormick_TaylorViewController.h"
#implementation McCormick_TaylorAppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (void)dealloc
{
[_window release];
[_viewController release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]
autorelease];
// Override point for customization after application launch.
self.viewController = [[[McCormick_TaylorViewController alloc]
initWithNibName:#"McCormick_TaylorViewController" bundle:nil] autorelease];
UINavigationController * navController = [[UINavigationController alloc]
initWithRootViewController:self.viewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
in your McCormick_TaylorViewController's viewWillApper: method
just use bellow code...
[self.navigationController setNavigationBarHidden:NO animated:YES];
and in other view controller in navigationbar ot display then in another viewController's viewWillAppear just use bellow code..
[self.navigationController setNavigationBarHidden:NO animated:NO];
Use this method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]
autorelease];
// Override point for customization after application launch.
self.viewController = [[[McCormick_TaylorViewController alloc]
initWithNibName:#"McCormick_TaylorViewController" bundle:nil] autorelease];
UINavigationController * navController = [[UINavigationController alloc]
initWithRootViewController:self.viewController];
[navController.navigationBar setHiden:YES]; // hides navigation bar
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
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
I have a problem with switching from one viewcontroller to another.
Here is what I have :
In my "AppDelegate_iPad.m" :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
CGRect frame = [UIScreen mainScreen].bounds;
window = [[UIWindow alloc] initWithFrame:frame];
window.backgroundColor = [UIColor blackColor];
LoginViewController_iPad *loginView = [[LoginViewController_iPad alloc] initWithNibName:#"LoginViewController_iPad" bundle:nil];
[window addSubview:loginView.view];
[self.window makeKeyAndVisible];
return YES;
}
That works. Now I have a login button on that screen and when pressed it calles this :
- (IBAction)doPressLoginButton
{
DebugLog(#"doPressLoginButton");
MenuViewController_iPad *menuView = [[MenuViewController_iPad alloc] initWithNibName:#"MenuViewController_iPad" bundle:nil];
[self.navigationController pushViewController:menuView animated:YES];
[menuView release];
}
The problem is that nothing happends. I assume I am missing the actual navigationconroller ?!
Hope that anyone can help.
Thank you
You should create a UINavigationController instance variable in your app delegate. Then, make sure you synthesize it and release it in your dealloc method.
Your implementation of application:didFinishLaunchingWithOptions: could look like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// window is usually an IBOutlet
CGRect frame = [UIScreen mainScreen].bounds;
window = [[UIWindow alloc] initWithFrame:frame];
window.backgroundColor = [UIColor blackColor];
LoginViewController_iPad *loginView = [[LoginViewController_iPad alloc] initWithNibName:#"LoginViewController_iPad" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:loginView];
[loginView release];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
Now you'll be able to use self.navigationController.
I assume I am missing the actual navigationconroller ?!
you are right. :D
self.navigationController returns nil if you don't set up an NavigationController.
And any messages send to nil object will be ignored.
If you only need switch from one to another.
using
[self presentModalViewController:modalViewController animated:YES];
instead.