I have a UITabBarController with 4 UINavigationControllers. I have implemented the didSelectViewController Delegate Method as follows:
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[UINavigationController class]]) {
[(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
}
}
It crashes when a NavigationController is at a 2nd Level after didSelectRowAtIndexPath pushes a new viewController onto the stack.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
RootViewController *detailViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
// ...
detailViewController.title = [self.temp objectAtIndex:indexPath.row];
detailViewController.sort = self.title;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Of course the debugger with NSZombies enabled doesn't give any feedback.
However, if I add retain to detailViewController alloc;
RootViewController *detailViewController = [[[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil] retain];
It works, but leaks memory.
Any ideas what is wrong, how to fix, what is happening?
I have the similar scenario and i came up with following solution.
In my application i have login screen at launch and then I have UITabbarController with 4 UINavigationControllers.
I have created property of UINavigationController in AppDelegate.h file.
#property (strong, nonatomic) UINavigationController *navigationController;
Then
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions
{
//Override point for customization after application launch.
LoginViewController *loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:loginViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
Now when you need to pop to RootViewController then use following code
#import "AppDelegate.h"
[((AppDelegate *)[[UIApplication sharedApplication] delegate]).navigationController popToRootViewControllerAnimated:YES];
Hope this solves your problem.
Related
I am building an iphone application.
I have a tabbarcontroller that has 2 tab items. Each tabitem links to a different navigationcontroller. Each navigationcontroller links to a hierarchy of tableviewcontrollers.
When a user clicks on tab 1, then clicks on an item in the table, then clicks tab 2, and then clicks on tab1, the application shows the table that he was just looking at before he clicked on tab2.
How do i get the app to show the first table of tab 1 every time he clicks on tab 1 instead of showing the most recent table he was looking at before leaving tab1?
I would prefer a programmatic solution as opposed to using xcode storyboard. But if none exists, then storyboard solution is fine too.
Call popToRootViewControllerAnimated: on the NavigationController when the TabBarController changes tab that is being displayed.
Try this basic sample to create a UItabBar and UInavigationController for each UItabBarItem from scratch :
in your header file (appdelegate.h) , add this delegate :
#interface AppDelegate : UIResponder <UIApplicationDelegate,UITabBarControllerDelegate>
in the function called "didFinishLaunchingWithOptions" , add this part of code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *navController=[[UINavigationController alloc] init];
m_ViewController1 = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil];
[navController pushViewController:m_ViewController1 animated:NO];
UINavigationController *navController2=[[UINavigationController alloc] init];
m_ViewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[navController pushViewController:m_ViewController2 animated:NO];
UITabBarController *mtabBarController = [[UITabBarController alloc] init];
mtabBarController.view.frame = CGRectMake(0, 0, 320, 460);
// Set each tab to show an appropriate view controller
[mtabBarController setViewControllers: [NSArray arrayWithObjects:navController1,navController1,navController2, nil]];
self.window.rootViewController = mtabBarController;
mtabBarController.delegate = self;
[self.window makeKeyAndVisible];
return YES;
}
Then in this function , don't forget to add the popToRootViewControllerAnimated function :
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
[m_ViewController1.navigationController popToRootViewControllerAnimated:YES];
[m_ViewController2.navigationController popToRootViewControllerAnimated:YES];
return YES;
}
in my appdelegate.h file, I changed the line
#interface wscAppDelegate : UIResponder <UIApplicationDelegate>
to
#interface wscAppDelegate : UIResponder <UIApplicationDelegate,UITabBarControllerDelegate>
Then in my CustomTabBarController in the viewDidLoad function i added these lines:
wscAppDelegate *appDelegate = (wscAppDelegate *)[[UIApplication sharedApplication] delegate];
self.delegate = appDelegate;
Then in appdelegate.m file, I added this function
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
for(int c=0; c<[tabBarController.viewControllers count]; c++)
{
UINavigationController * navcontroller = [tabBarController.viewControllers objectAtIndex:c];
[navcontroller popToRootViewControllerAnimated:YES];
}
return YES;
}
I've tried every solution on Google and nothing seems to work. So far I've implemented a UINavigationController with the App Delegate, now all I want to accomplish is changing to the WebViewController by clicking the UIButton I've created in the interface builder, but the button doesn't seem to do anything when I run the application. Keep in mind that I want it to push to my WebViewController view.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
ViewController.m
- (IBAction)createFile:(id)sender {
WebViewController *webViewController = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:NSBundle.mainBundle];
[self.navigationController pushViewController:webViewController animated:YES];
}
Note: In the interface builder I've already connected createFile to the button.
I understand that this is usually something that comes known as super easy but for some reason I've just never gotten it to work. Thanks in advance.
EDIT: I added the retaining property, sythesized it and added to my code in the ViewController.m file:
WebViewController *webViewController = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:NSBundle.mainBundle];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:webViewController];
[self.navigationController pushViewController:webViewController animated:YES];
But now the app crashes on the button click and returns with a SIGABRT: "Pushing the same view controller instance more than once is not supported (WebViewController: 0x1ed70e80)"
give this a try
-(IBAction)createFile:(id)sender{
WebViewController *webViewController = [[WebViewController alloc]
initWithNibName:#"WebViewController" bundle:nil];
webViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:webViewController animated:YES];
}
One thing i noticed is that you are not retaining your navigationController in the appDelegate. So what may be happening is that your the navigationControllers view may be present and retained (from the all to addSubView) but the navigation controller may have been deallocated.
in your AppDelegate try making the Navigation Controller a retaining property
#property (nonatomic, strong) UINavigationController *navigationController
in your .m file
#synthesize navigationController
and then
Edit: Updated for pushing a view controller
WebViewController *webViewController = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:NSBundle.mainBundle];
[self.navigationController pushViewController:webViewController animated:YES];
I have a tab-bar based app. When the app becomes active, I want it to go to the second tab bar (SecondViewController) and then, open DetailViewController.
Here's how I'm doing it:
AppDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application {
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:1];
SecondViewController *secondView = [[SecondViewController alloc] init];
[secondView openDetailView];
[secondView release];
}
SecondViewController.m
-(void)openDetailView{
NSLog(#"open detail view");
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[[self navigationController] pushViewController:detailViewController animated:YES];
}
openDetailView() does run (as I see the nslog working), but the DetailView does not get pushed? I know the code works because I have identical code in an IBAction which DOES push the detailView. The problem has something to do with it being called from the AppDelegate (or switching tabs).
So why doesn't the view get pushed when I call it from the App Delegate? Any help is greatly appreciated.
You push detailViewController to the Navigation-Stack of secondView, but secondView is in nowhere.
Try this...
SecondViewController *secondView ...
[self.tabBarController pushViewController:secondView animated:YES]; <==
[secondView openDetailView];
I have the following code in my AppDelegate:
#import <UIKit/UIKit.h>
#class PersonalDiarySystemViewController;
#interface PersonalDiarySystemAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
PersonalDiarySystemViewController *viewController;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet PersonalDiarySystemViewController *viewController;
#property (nonatomic, retain) UINavigationController *navigationController;
#end
#import "PersonalDiarySystemAppDelegate.h"
#import "PersonalDiarySystemViewController.h"
#implementation PersonalDiarySystemAppDelegate
#synthesize window;
#synthesize viewController;
#synthesize navigationController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Set the view controller as the window's root view controller and display.
self.window.rootViewController = self.viewController;
navigationController = [[UINavigationController alloc] initWithRootViewController:self.window.rootViewController];
navigationController.navigationBar.tintColor = [UIColor
colorWithRed:217.0/255
green:33.0/255
blue:0
alpha:1];
navigationController.navigationBarHidden = YES;
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
My rootviewcontroller tries to load another viewcontroller into the navigation controllers stack in its viewDidLoad method but for some reason the view is not getting pushed:
-(void) viewDidLoad{
lvc = [[LoginViewController alloc] init];
//lvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[lvc setDelegate:self];
//[self presentModalViewController:lvc animated:YES];
[self.navigationController pushViewController:lvc animated:YES];
}
I'm getting no errors so not sure whats going on...using presentModalViewController works...so really am confused!!
You need to assign lvc to LoginViewController.
- (void) viewDidAppear
{
[self performSelector:#selector(loginCheck:) withObject:nil afterDelay:0.5];
}
- (void) loginCheck:(id)sender
{
LoginViewController * lvc = [[LoginViewController alloc] init];
//lvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[lvc setDelegate:self];
//[self presentModalViewController:lvc animated:YES];
[self.navigationController pushViewController:lvc animated:YES];
}
Put your
[self.navigationController pushViewController:loginViewController];
Into the
- (void)viewDidAppear:(BOOL)animated
method. The viewControllers navigationController doesn't get loaded until then
There are two things that might go wrong.
First, you alloc the navigation controller in applicationDidFinishLaunching, I'm not quite sure which goes first, applicationDidFinishLaunching or viewDidLoad.
As you've seen, you first set your root view controller, then alloc the navigation controller, then maybe viewDidLoad launched right after you set the root view controller, then the navigation controller is allocated. so the words in viewDidLoad may not work because at that time, the navigation controller hasn't been born yet.
But I don't' quite thing the previous explanation works. it's just a possibility.
There's another strange thing, you set the navigation bar of your navigation controller hidden
navigationController.navigationBarHidden = YES;
Then it seems that the user can't pop back to the root view controller, so the navigation controller don't push the login view controller.
Meanwhile, the modal view controller can be dismissed with the navigation bar hidden or the navigation bar not allocated, so it works when you present it as a modal view controller.
but i'm still not quite sure about it since i'm now having some issues with Xcode, so i can't test the previous two ideas, sorry about that. but i still recommend that you set navigationBarHidden to NO.
- (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.navController = navigationController;
[mainViewController release];
[navigationController release];
// Configure and display the window.
[window addSubview:navController.view];
[window makeKeyAndVisible];
}
- (void)viewDidLoad{
lvc = [[LoginViewController alloc] init];
[self.navigationController pushViewController:lvc animated:YES];
}
I have a popup tableview (ViewController2) appearing when I click a button on ViewController1. Then when I select a row in the table, I want those values to be sent back to ViewController1. I have a NSDictionary set up. It works fine in a regular navigation controller, but trying to do it with dismissModalViewControllerAnimated, so the tableview drops back down, and the data is appearing in the first view.
This is similar to this question here I think: http://www.iphonedevsdk.com/forum/iphone-sdk-development/39995-return-data-dismissmodalviewcontrolleranimated.html
Here is my code:
ViewController1.h:
#protocol ViewController1Delegate;
#interface ViewController1 : UIViewController <ViewController2Delegate> {
id <ViewController1Delegate> delegate;
}
#property (nonatomic, assign) id <ViewController1Delegate> delegate;
#end
#protocol ViewController1Delegate
- (void)viewController1DidFinish:(ViewController1 *)controller;
#end
ViewController1.m:
-(void)buttonGoToViewController2 {
ViewController2 *controller = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
// this controller.delegate = self causes it to crash if i have it uncommented for some reason...
// controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}
ViewController2.m:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(searching) {
// Navigation logic may go here. Create and push another view controller.
NSDictionary *selectedCountry = [self.copyListOfItems objectAtIndex:indexPath.row];
ViewController1 *dvController = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil andDictionary: selectedCountry];
NSLog(#"selected hit this %#",selectedCountry);
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
[self dismissModalViewControllerAnimated:YES];
}
else {
// Navigation logic may go here. Create and push another view controller.
NSDictionary *dictionary = [self.listOfItems objectAtIndex:indexPath.row];
ViewController1 *dvController = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil andDictionary: dictionary];
NSLog(#"normal hit this %#",dictionary);
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
}
}
In your ViewController2 code you are creating a new ViewController1 object and giving it your NSDictionary. When you dismiss ViewController2 you go back to the original ViewController1, which never went anywhere and was never sent the NSDictionary. You need to provide ViewController2 with access to the ViewController1 object that presented it (I suggest doing it via a delegate pattern) in order to set the NSDictionary there.