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.
Related
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.
I am working on an iPhone app using Storyboard and I need to handle view changes from one view controller to another one. I have:
-INTROViewController.m
-INTROscene.m (this is a SKScene laid out by the above controller)
-UpgradeViewController.m
There is a sprite button in INTROscene.m and when I press it, it triggers a notification which is seen by its view controller (INTROViewController.m) and this triggers the switch to another view controller (UpgradeViewController.m). If I use Option 1, (which even adds a delay in order to make sure that the first view has appeared), it triggers the error below:
“Attempt to present ViewController whose view is not in the window hierarchy!”
I’ve found a way of switching view controllers without triggering this error (Option 2) but the visual effect is horrible, with a little lag showing an empty screen between the two views. Moreover I cannot use any of the nice transitions which are available using modalTransitionStyle.
What is the correct way of switching between views in this situation?
In my AppDelegate I don’t have a root view controller (and I don’t know how this should be set up). Is that the reason why I get the error? If so, how could I implement it? Cheers!
//Option 1 (triggers the error above)
-(void)TransitionTo_Upgrades_ViewController:(NSNotification *)notification
{
//Take from INTROViewController to UpgradeViewController
UpgradeViewController *controllerUPGRADES = [self.storyboard instantiateViewControllerWithIdentifier:#"Upgrades_storyboard"];
controllerUPGRADES.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self performSelector:#selector(NowGotoUPRADES) withObject:nil afterDelay:2.0];
}
- (void)NowGotoUPRADES
{
[self presentViewController:controllerUPGRADES animated:YES completion:nil];
}
//Option 2 (no error but horrible effect)
-(void)TransitionTo_OPTIONS_ViewController:(NSNotification *)notification
{
[self performSelector:#selector(NowGotoOPTIONS) withObject:nil afterDelay:2.0];
}
- (void)NowGotoOPTIONS
{
//Take from INTROViewController to UpgradeViewController
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UIViewController *DesiredViewController = [storyBoard instantiateViewControllerWithIdentifier:#"Options_storyboard"];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:DesiredViewController];
}
I have experienced this same problem and have found that there is no solution as once you move from scene to scene in a view controller, you are unable to move to other view controllers as you have moved out of the proper hierarchy. My solution to this was to have my other view controllers as skscenes, however you may want to have most of your skscenes as view controllers whilst also not moving between scenes whilst on the same view controller.
Hope this helps. Reply if you need any clarification.
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 am having major memory management issues. After small use of the program it will crash running out of memory. I have finally found the cause, every time I create a new ViewController rather than accessing the instance, I am creating a new instance.
So app loads and instantiates the FirstViewController. You click a button which instantiates FilterViewController. From here when going back to FirstViewController I am creating a new instance of this as follows:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName
:#"MainStoryboard" bundle:nil];
FirstViewController *fvc = [storyboard
instantiateViewControllerWithIdentifier:#"FirstViewController"];
fvc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
And repeat process. Any way of presenting the view controller without re-instantiating it? I am close to submitting the app (tomorrow hopefully) so I need to try get this sorted. Thanks!
Here is the presentation of the ViewController.
[self presentViewController:fvc animated:YES completion:nil];
Presenting FilterViewController from FirstViewController
- (IBAction)searchOptions:(id)sender {
FilterViewController *ctrl = [[FilterViewController alloc] init];
[UIView transitionFromView:self.view toView:ctrl.view duration:1 options:UIViewAnimationOptionTransitionCurlUp completion:nil];
self.filterViewController = ctrl;
[self.navigationController pushViewController:self.filterViewController animated:NO];
}
If you're using presentViewController, you get back to the previous view by calling [self dismissViewControllerAnimated:YES];. You would do that in the method where you're currently creating the new controller.
If you are pushing into a navigation controller you would pop from the navigation controller: [self.navigationController popViewControllerAnimated:YES];.
Based on your last update it seems like you don't have a navigation controller and you're just adding the view as a subview and storing the filter view controller. That makes life more complicated really and the correct way to remove it is to setup a delegate relationship so that the filter view controller calls back to the first view controller when it's done and the first controller then transitions the views and nil's the reference.
If you can, change to use a navigation controller properly. You already have half the code, but the first view controller seems to not be in a navigation controller. If you use a nav controller life will be easy...
What i'm doing is this:
UIViewController *rootController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
AlarmRingViewController *alarmController = [[AlarmRingViewController alloc] init];
[rootController presentViewController:alarmController animated:YES];
What i want to achive with this, is to push my AlarmRingViewController on top of any other controller which is displaying at the moment and it works so far.
Now im wondering if this is good practice:
to instatiate a new viewController each time it should be presented
do so in a non UI related class? (in my case a scheduler for NSTimer)
from there push the newly created viewController with the rootViewController on top
Or does this violate the MVC pattern or Apples guidelines or anything.
cheers
Personally I think it's ugly code. It's hard to read and hard to debug. Split the code up a bit:
UIViewController *rootController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
AlarmRingViewController *alarmController = [[AlarmRingViewController alloc] init];
[rootController presentViewController:alarmController animated:YES];
There is no benefit to typing so much into one line.
Update: Based on your updated question:
There is no problem instantiating a new view controller each time you need it. This is very common. It might be appropriate to create one and cache it. This is an optimization that could make sense if only one of the view controllers is every shown at any given time, the view controller is used very often, and it takes a lot of time to create.
View controllers are usually created and presented by other (view) controllers.
Why don't you just use a UINavigationController as the root view controller. That way, you can just do this:
AlarmRingViewController *alarmController = [[AlarmRingViewController alloc] init];
[self.navigationController presentViewController:alarmController animated:YES completion:nil];