We have a tab bar + navigation control project. We have created a tab bar through interface builder and added all tab items to the tab bar controller through through interface builder.
Our application has a login screen which we are showing as a modal form at the beginning. Once the user is authenticated, the login screen is dismissed (using dismissModalScreen) and the MainWindow is shown. This is all working fine.
Now, we have a logout option clicking on which we should show the login screen back. We are able to show that as well. But the issue is once the user is authenticated again, we want all the screens to be loaded freshly. Currently, all screens maintain their state and retain previous data.
What we have tried to do is:
[AppDelegate tabBarController release];
AppDelegate.tabBarController = nil;
We have tried releasing the tabBarController and setting it to nil. But once the view is shown, we are not able to select any of the tabs and the view is blank.
What we need is:
Once the user logs in second time, how to release and reload each viewcontroller which are part of tabbar.
Your help will be greatly appreciated.
We have found a way out. What we are doing now is, once the user logs back in, we are releasing the view controllers and recreating them and setting it back to the uitabbar.
NSMutableArray *arrControllers = [[AppDelegate.tabBarController.viewControllers] mutablecopy];
[arrControllers removeAtIndex:3];
[arrControllers removeAtIndex:2];
----Create New Controllers
UIViewController viewController2 = [[UIViewController alloc] initWithNibName:#"viewController2" bundle:nil] autorelease];
UIViewController viewController3 = [[UIViewController alloc] initWithNibName:#"viewController3" bundle:nil] autorelease];
--Create Nav controller
UINavigationController navViewController2 = [[[UINavigationController alloc] initWithRootViewController:viewController2 ] autorelease];
UINavigationController navViewController3 = [[[UINavigationController alloc] initWithRootViewController:viewController3 ] autorelease];
[arrControllers addObject:navViewController2];
[arrControllers addObject:navViewController3];
[AppDelegate.tabViewController setViewControllers:arrControllers];
It is working fine after this change.
Only problem we faced was if we release all objects from the array, we get a carsh. Is it because, when you release allObjects, the first controller which is the RootViewController is getting released?
Thanks
Related
I am trying to change the action executed by pressing the backBarButtonItem of a Navigation Controller.
I know that i have to edit the backBarButtonItem before the next view (on which the button with custom behavior should appear) is pushed. So in the previous ViewController i added the following code, to push via segue:
#pragma mark - segue methods
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"SettingsToProfile"]) {
MyProfileViewController* myprofileVC = [segue destinationViewController];
myprofileVC.myProfile = myProfile;
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Settings_" style:UIBarButtonItemStylePlain target:myprofileVC action:#selector(popTOSettingsViewController:)];
} else {
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Settings" style:UIBarButtonItemStylePlain target:nil action:nil];
}
}
The title "Settings_" gets displayed correctly, but "target: myprofileVC action:#selector(popTOSettingsViewController:)" doesn't seem to have any effect at all.
Background:
MyProfileViewController is a View, where the user can edit his/her own information. Whenever the backbarbutton is clicked, i want to check if something in the GUI has been changed by the user. If thats the case, a UIAlterView should ask the user, if he/she wants to save the changing. I tried to work it out with, viewWillDissappear, but the AlterView gets displayed in the next ViewController (and program crashes, if i click on the alterViewButtons).
I'm not sure that you can change the target of a backBarButtonItem. How about self.navigationItem.leftBarButtonItem instead? There's a discussion at self.navigationItem.backBarButtonItem not working ?? Why is the previous menu still showing as the button? that may be relevant.
I am presenting a popover with my viewcontroller:
UIBarButtonItem *barButton = (UIBarButtonItem*)sender;
SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:nil bundle:nil];
[self presentPopoverFromBarButtonItem:barButton andController:settingsViewController andSize:CGSizeMake(RECT_POPOVER_SETTINGS.size.width, RECT_POPOVER_SETTINGS.size.height)];
and inside this view controller I have a button that pushes another view controller.
AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:anotherViewController animated:YES];
Now in this view controller I have an action, and when it's done I do:
[self.navigationController popViewControllerAnimated:YES];
Now the strange behavior is that when I pop the view controller, the
viewWillAppear
method gets called in SettingsViewController, then the breakpoints come back to pop method inside my anotherViewController.
This is a universal App so I am using this same setup on the iPhone, but without the initial UIPopOverController. This is functioning properly in the iPhone (with no popovers, pop method gets called first, then viewWillAppear), but on the iPad the viewWillAppear gets called first, then pop.
So my question is, can somebody explain why this is happening?
Thanks.
I have a Navigation Controller based app. From my Root VC, I have one view that I present modally like this:
[self.navigationController presentModalViewController:shortcutsViewController animated:YES];
shortcutsVC contains a row of buttons, which take the user to various places in the app.
In iOS 4.3, this works:
UINavigationController *saveNavigationController = (UINavigationController *)self.parentViewController;
[saveNavigationController pushViewController:multipleListViewController animated:YES];
[saveNavigationController dismissModalViewControllerAnimated:YES];
[multipleListViewController release];
It does not work if the dismiss happens before the push.
In iOS 5, it doesn't work at all, regardless of which order the two commands are in.
By "not work" I mean that the button highlights briefly but the new VC is not displayed.
What is the right way to do this? Or am I doing something that was illegal all along and just happened to work in 4.3?
EDIT:
I got some offline help on this one.
The problem is that in iOS5, parentViewController has been renamed presentingViewController. Since I still need to support both 4.x and 5.x, I changed this
UINavigationController *saveNavigationController = (UINavigationController *)self.parentViewController;
to this
UINavigationController *saveNavigationController;
if ([self respondsToSelector:#selector(presentingViewController)]) {
saveNavigationController = (UINavigationController *)self.presentingViewController;
} else {
saveNavigationController = (UINavigationController *)self.parentViewController;
}
And all is happy now.
I am building my first iPad application. And one of my requirements is to deal with UISplitviewcontroller and UINavigationController.our proposed view hierarchy is (LoginView) ->UINavigationView(LandingView + CollectionView)->UISplitViewcontroller( DetailsView).Our app supports only landscape mode
I am referring this SO Question( and GILT app as well), as a newbi its hard for me to get it done based on that description.
So my questions are
1) How can I achieve same thing,if somebody can give small code snippets or reference to tutorial
2) As per Apples HIG, UISplitviewcontroller should be rootviewcontroller,what if it not. Will apple reject my app.(apparently GILT group has been approved)
3) I found MGSplitViewController , can I use that one not as root?
Any help would be appreciated. As a newbi i hope my question is genuine
If you want to use the out-of the box splitView it must be root; any hokeary-pokery here will either break apples guidelines or manifest very odd behaviour.
The MGSplitViewController is completely custom implementation of a SplitViewController. Its very good if you need that sort of thing, but some of the features are based round the fact that our app will be orientating.
Alternatively you could make your own. I have done this more than once and is easier than it sounds.
(LoginView)
->UINavigationView(LandingView + CollectionView)->UISplitViewcontroller(
DetailsView).
Based on an out-of-the-box UISplitView, I would suggest:
Make the splitView the root View.
Pop (not animated) a full screen Modal as soon as the app starts and allow the
user to navigate the loginView,
LandingView and collectView in this; i also recommend using a navController here.
Once the user is ready to proceed to
the splitView, populate the
splitView's rootView Controller and
DetailViewController with whatever
you want then ,animate the Modal out.
Dave does have a point, but i would look at it from the point of view that you are removing the choice of orientation from the user; removing standard choices (like supported orientations) because the designer assumes some configuration is more efficient will only annoy some users.
I did it by making a method in my detailViewController:
-(void)popHomeScreen:(BOOL)animated//OPENS THE HOMESCREEN IN A MODAL DISPLAY
{
firstRun=NO;
//myViewControllerForPopOver init here
myViewControllerForPopOver.modalPresentationStyle = UIModalPresentationFullScreen;
myViewControllerForPopOver.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;//simple anime
if (animated) [self presentModalViewController:myViewControllerForPopOver animated:YES];
else [self presentModalViewController:myViewControllerForPopOver animated:NO];
}
Then Call it in the detailViewControllers ViewDidAppear method:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if(firstRun)[self popHomeScreen:NO];
}
//YOU WILL ALSO NEED TO MAKE 'firstRun=YES' in viewDidLoad
//firstRun is a BOOL
As for the root disappearing (leaving a big black space)..thats a known bug. though i thought for a while that it was caused by ordering an animation while/just before it was going to draw itself.
Also, i found that if i popped a full screen modal over the splitView then popped another form based modal (for example) quickly after it the full screen modal didn't draw properly.
SplitViews are like your mother-in-law, you don't really like them and when you have to use them you have to tip-toe round the landmines.
Try this, it works for me
1) in app delegate's didFinishLaunchingWithOptions make your login view to root view
self.window.rootViewController = self.loginViewController;
also, init the split view as the template do ( but not add to self.window)
MasterViewController *masterViewController = [[[MasterViewController alloc] initWithNibName:#"MasterViewController_iPad" bundle:nil] autorelease];
UINavigationController *masterNavigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];
DetailViewController *detailViewController = [[[DetailViewController alloc] initWithNibName:#"DetailViewController_iPad" bundle:nil] autorelease];
UINavigationController *detailNavigationController = [[[UINavigationController alloc] initWithRootViewController:detailViewController] autorelease];
self.splitViewController = [[[UISplitViewController alloc] init] autorelease];
self.splitViewController.delegate = detailViewController;
self.splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavigationController ,detailNavigationController, nil];
2) add a swap view controller in app's delegate, which swap the root view to split viewcontroller.
-(void)swapToViewControllers:(RootViewControllerType)viewType
self.window.rootViewController = self.splitViewController;
3) invoke the swapToViewControllers in your login view.
Keep in mind that the HIG strongly encourages you to support all orientations. Unless you have a very, very good reason to support landscape only, you'll probably be rejected.
See page 19 of the HIG: http://developer.apple.com/library/ios/documentation/General/Conceptual/iPadHIG/iPadHIG.pdf
Modified Ryan CY's version with storyboard.
Put this code to login controller.
1. Set storyboard id of UISplitViewController to SplitViewController;
2. Set UISplitViewController delegate and save instance
UISplitViewController* splitController = [self.storyboard instantiateViewControllerWithIdentifier:#"SplitViewController"];
UINavigationController* navigationController = [splitController.viewControllers lastObject];
splitController.delegate = (id)navigationController.topViewController;
3. Change rootViewController after login
self.view.window.rootViewController = splitController;
I have a UITabBarController whose tabs are UINavigationController. I have initialized each navigationController by:
iPhoneApp *appDelegate = (iPhoneApp *)[[UIApplication sharedApplication] delegate];
[appDelegate.navigationController2 initWithRootViewController:countryController];
I then drill down the navigationController with:
[self.navigationController pushViewController:myViewController animated:YES];
I want to pop to the root of my navigationController(s) when the user clicks on a tabBar tab.
[delegate.navigationController2 popToRootViewControllerAnimated:NO];
This seems to work great when I only pushViewController one level, but fails when I drill down multiple levels in my navigationController. What happens is that it pops to root but doesn't contain my Root's backbutton or title:
self.navigationItem.title = #"My title";
self.navigationItem.hidesBackButton = YES;
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleDone
target:self
action:#selector(handleBack:)];
if I don't poptoroot and just use the navigationControlls back button, everything works correctly.
I logged my viewControllers before and after i poptoroot
before:
MainCountryController: 0x3d53650,
IndividualCountryMfgViewController: 0x3d67d50,
IndividualCountryProductViewController: 0x3d60870
after:
MainCountryController: 0x3d53650
it's the right view, but wrong toolbar title and backbutton.
Anyone have any ideas? Thanks for your help.
I got this working by disconnecting my navigation controllers from IB an just creating them programatically.