I have a viewController A which will both added into viewController hierarchy by being pushed by view B(presented) and being pushed by view C(pushed).
ROOT->...-(-present-)->B-(-push-)->A
ROOT->...-(-push-)->C-(-push-)->A
And now I have a button in viewController A which needs to change the window.rootViewController, but I cannot make it functions correct in both conditions.
When I use [self.navigationController popToRootViewControllerAnimated:<#(BOOL)#>];, it will not dismiss the presented view B.
Also [[[UIApplication sharedApplication] keyWindow].rootViewController dismissViewControllerAnimated:YES completion:<#^(void)completion#>]; is not the solution, because when there is no presented view completion block will not be called.
If I combine those two methods, I think it will work only when I pass a parameter to every viewController in the hierarchy.
So is there a rough way to clear the viewController hierarchy?
Or is there any other solution?
You can set rootViewController from anywhere in application like,
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
appDelegate.window.rootViewController = #"desired root VC"; // instatntiate your VC and set as root VC of your window
And don't forget to implement AppDelegate.h in that class.
Related
So after a lot of research if finally found the code that allows me to change to another view without giving me any errors:
UIViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"gameOverPage"];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:vc];
The only problem with this code is that there is no animation. I want to somehow add the cross dissolve animation to this if possible.
Another major problem is that it shows the view two times (some times three). So it goes to the second view and then less than a second later, it shows the page again. I know this because iAd is reloaded and when I press a button that goes to another page, it is interrupted by the second page coming up again.
To change the view to another (navigating) you don't need to setRootViewController: set it as root view controller always.
you can use a UINavigationController and set a UIViewController as root, then to change view use pushViewController: method of navigation controller, like
//Pre condition - already a viewController is root view controller of navigation controller.
UIViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"gameOverPage"];
[self.navigationController pushViewController:vc animted:YES];
Another way is,
[self presentViewController:vc animated:YES completion:nil];
Read more presentViewController, UINavigationController
I want to navigate to the initial view from almost any View Controller in my storyboard. I don't want to create a segue manually for every view to the initial view. Is there a nice and handy way to do this in one line, or maybe a method that my other VC could inherit?
The best way to do this (in my opinion) would be using a UINavigation Controller.
Make the UINavigation Controller the root view controller of your storyboard, then connect it to your "actual" root view controller.
Then, from any view controller that has been pushed with the navigation controller, you can do:
[self.navigationController popToRootViewControllerAnimated:YES]; // or NO
You can keep a strong reference to the initial/root view controller you want in the AppDelegate, and then setup a method within it that you call from anywhere to switch the current view controller to your initial controller.
You would do something like this in the AppDelegate.h file:
#property (strong, nonatomic) MyInitialViewController *initialViewController
- (void)switchToInitialViewController;
In the AppDelegate.m you can do:
- (void)switchToInitialViewController
{
self.window.rootViewCotroller = self.initialViewController;
}
And then you can do this from any method:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate switchToInitialViewController];
And that, hopefully, helps. :)
Why don't you go for
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifer isEqualToString:#"identifier"]) {
// Put your code here....
}
}
Every ViewController have this kind of method inside and you can move to other controller or your intial Controller. and if you're using NavigationController then you can go for
#Eric answer.
i have a navigation controller which is my application's root view controller. it is my main screen. I have a split view controller whose master view lists location and detail view shows the location on the map. I wanted to push the split view controller to the navigation controller, but it throw a error saying split view controller cant be pushed to navigation controller and it must be application's root view controller.
So i tried a hard way.
MyAppDelegate *myappdelegate= [[UIApplication sharedApplication] delegate];
UISplitViewController * vc= [[UISplitViewController alloc] init];
vs.viewControllers = [NSArray arraywithObjects......
....
myappdelegate.window.rootViewController= vc;
This works. It shows split view controllers without animation as expected. And i do the same steps when i was closing split view controller. i am creating a navigation controller with main screen nib and setting this my app delegate's window.rootviewController again.
And it succesfully loads main screen again.
But i suspect that this is the proper way of achieving this. Is there more eligible way of doing this?
And i couldnt release split view controller's child controllers. i made a breakpoint on my release method of child controllers. it wasnt be catched. I assumed that when i set my app's root view controller as navigation controller, the old root view controller (split view controller) must be released along with its childs.
Then i tried below code when closing split view controller.
UISplitViewController *oldviewcontroller= (UISplitViewController*) myappdelegate.window.rootViewController;
for (UIViewController *child in oldviewcontroller.viewControllers)
{
[child release];
}
//Setting the navigation controller as window.rootviewController again in here.
This code throw an error saying "[UIImageView __viewDidDisappear:]: unrecognized selector sent to instance 0x7d...."
i think because of releasing the view already, there is no imageview on viewdidDisappear event.
In brief, my question is that am i using right method to achieve this? If so, how can i successfully release all child view controllers?
I finally found a way. I probably found the error. What i have done is cutting the branch on which i am sitting. I was releasing the view controller which i am currently in:) When viewdidDisappear called, there is no such view controller. Because i throw away it to space already.Below is my working steps. I hope it will be useful to someone. But i cant stand thinking of apple may reject my app. I wish finding a suitable way.
This is my working ultimate way of using split view controller and navigation controller as window root view controller alternately.
Firstly i defined NavigationController and SplitViewController property in AppDelegate interface.
AppDelegate.h
#property (assign,nonatomic) UINavigationController * NC;
#property (assign,nonatomic) UISplitViewController *SVC;
Secondly i assign newly created NC on AppDelegate didFinishLaunch event.
AppDelegate.m
//Creating my main screen controller
//Creating my navigation controller with my view controller instance. Then
self.NC= my_navigation_controller;
self.window.rootViewController= self.NC;
Thirdly creating a splitview controller and setting as app's root view controller
MyMainScreen.m
-(void) OpenSplit()
{
//Creating my master view controller of SVC
//Creating my detail view controller of SVC
//Creating my SVC;
AppDelegate * app_delegate= [[UIApplication sharedApplication] delegate];
app_delegate.SVC= newly created my SVC;
app_delegate.window.rootViewController= app_delegate.SVC;
}
Fourthly releasing unused NC in viewDidLoad event of detail view of SVC.
MyDetailView.m
- (void) viewDidLoad()
{
...
AppDelegate * app_delegate= [[UIApplication sharedApplication] delegate];
app_delegate.NC= nil; //i dont need it now. i am releasing. Releasing Navigation Controller release as well child controllers. I learned with testing.
}
Fifthly managing close split view function.I used UIBarButton on NavigationBar in DetailView.
MyDetailView.m
-(void) closeSplitView
{
//Creating navigation controller with my main screen view controller
AppDelegate * app_delegate= [[UIApplication sharedApplication] delegate];
app_delegate.NC= newly_created_NC;
app_delegate.window.rootViewController= appdelegate.NC;
}
Sixthly handling unused split view controller in Main Screen viewDidLoad event.
MyMainScreen.m
-(void) viewDidLoad
{
AppDelegate * app_delegate= [[UIApplication sharedApplication] delegate];
app_delegate.SVC= nil; //I am releasing it because i am working with NC now.
}
I'm having a few problems integrating Greystripe adverts (documented here but not important). A way around my problem if to just present my gameView like this
iSlideAppDelegate *appDelegate = (iSlideAppDelegate *)[[UIApplication sharedApplication] delegate];
UIStoryboard *storyboard = self.storyboard;
Game3ViewController *gameView = (Game3ViewController *)[storyboard instantiateViewControllerWithIdentifier:#"mainGameController"];
[appDelegate.window addSubview:gameView.view];
This is basically just adding my gameView on top of the current view controller.
Now from this view I want to show another modal view like this
FullScreenSelfAdViewController *adView = [[FullScreenSelfAdViewController alloc] initWithNibName:#"FullScreenSelfAdViewController" bundle:nil];
[adView setDismissDelegate:self];
[self presentModalViewController:adView animated:YES];
The problem is, when this view is displayed, my gameView deallocates. Meaning when I call to dismiss the AdView it dealloc's but stays on screen as the underlying gameView isn't there any more.
Is there a better way to call these views? (I can't call my gameView by presenting it as a modal view).
Or a way to keep the gameView from deallocating?
If I had to guess, you don't have a strong variable retaining the class that gets dealloced. Whoever creates that class should have a strong ivar doing so. I had this exact same problem when I tried to create an object and use it without retaining it. Note that for UIAlerts, the system retains it when you call [alert show], leading to think you can do this with other view controllers (which you cannot!)
Good luck.
How to perform this better. For example, I have a button in my toolbar which must perform something like this:
[self.navigationController popViewControllerAnimated:YES];
Any ideas? Except of:
1)Defining the toolbar and it items inside the UIViewController subclass. It works for current view only.
2)Creating a pointer to navigation controller inside the toolbar.
Usually you can get access to UINavigationController from appDelegate
UINavigationController *navigationController = [(YourAppDelegate*)[[UIApplication sharedApplication] delegate] navigationController]; //navigationController is a property in appDelegate
But more effective approach is to make delegate method inside your custom toolbar and then handle actions in target UIViewController.