I currently have a main web view (UIViewController) that presents a UIViewController like this:
[self presentViewController:controller animated:YES completion:nil];
I am trying to observe when the presented view controller gets dismissed using:
[self dismissViewControllerAnimated:YES completion:nil];
I have tried observing a variable in the main web view that the presented view sets when it's being dismissed, but that doesn't seem to work.
How would I go about observing when the presented view gets dismissed?
Any help would be appreciated.
Thanks.
Can you put some code in the viewWillDisappear method? You're not clear on why you actually want to observe the variable. However this method will be called just before the view moves off. Conversely you can run code in the viewDidDisappear which is run after the view pops.
Related
I have one view controller MainViewController which (through buttons) allows the user to present/dismiss another InventoryViewController modally.
A third view controller CallViewcontroller is then presented programmatically from MainViewController at specific timed intervals. Before this happens, InventoryViewController is dismissed.
If InventoryViewController is never presented, CallViewController is presented without any problems.
If InventoryViewController is visible/present when CallViewController is launched, there also don't seem to be any issues.
But if InventoryViewController is presented then manually dismissed by the user, at any point, when CallViewController is presented the app partially freezes and the console throws an error -
Warning: Attempt to present <CallViewController: 0x17e31bb0> on <MainViewController: 0x18d3fc00> whose view is not in the window hierarchy!
Code to launch InventoryViewController from MainViewController:
[self performSegueWithIdentifier:#"segueToInventoryView" sender:self];
Code to dismiss InventoryViewController from a button from within MainViewController:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
Code to dismiss InventoryViewController programmatically from MainViewController just before CallViewController is presented:
[self dismissViewControllerAnimated:NO completion:nil];
(I also use a timer to delay the method that presents CallViewController to make sure InventoryViewController has been properly dismissed)
I'm guessing that the error is saying that I can't present a modal from MainViewController because it isn't at the top of the stack, suggesting that InventoryViewController hasn't been properly dismissed.
Originally my code was written for iOS7, now the BaseSDK is iOS9 ( I am returning to this project and iOS programming generally after a year). As far as I am aware, this problem didn't occur before. So is this being caused by changes brought on by iOS8/9, or is there something else happening here?
Any help appreciated.
Found the solution, I had a flag in MainViewController for checking if InventoryViewController had been dismissed, which wasn't being set correctly. This was causing [self dismissViewControllerAnimated:NO completion:nil] to be called twice, and the second time round it was actually dismissing MainViewController, by sending the call to it's parent!
So the fact that [self dismissViewControllerAnimated:NO completion:nil] can be called on both the presenting and presented view controller is perhaps something to watch out for.
The code outlined above all seems to work fine in iOS8/9
I have an app where I re-init the app if it's been in the background for too long. When the user opens up the app after the allotted time, the re-init happens, and I display the splash screen while I get the data I need. When I get the data from the server I set the window.rootViewController property to a new value. If the old root view controller has had a view controller presented modally, and that view controller was being displayed when the re-init happens, dealloc doesn't get called on the view controller (I've tested this by putting NSLog's in the dealloc method). In the case where a modal view controller was not presented, the dealloc gets called as expected.
Does anyone know of a solution to this? I'm not sure if it's an Apple bug, or if it's something that I need to handle on my own.
The solution that I came up with was before I set the RootViewController, I call
- (void)_dismissRootViewControllersModalViewsIfAny {
UIViewController *rootViewController = self.window.rootViewController;
if (rootViewController.presentedViewController || rootViewController.presentingViewController)
{
[rootViewController dismissViewControllerAnimated:NO completion:nil];
}
}
This is a method that I created, which makes sure that if there is a modal view controller to dismiss, it will be dismissed.
Your modal view is presented by the rootViewController (it's presentingViewController property is set to the rootViewController), that might be the source of your problem.
You can set your rootViewController to an instance of UINavigationController and then just use its setViewControllers:animated: method to display a freshly instantiated view controller instead of switching the window's rootViewController.
I'm trying to create a small game where the user moves over an object and displays another view controller to display information. Upon pressing a button on the recently presented view controller, the view gets dismissed and shows the view controller I started off with. I've done this like this:
ViewController.m
OtherViewController *other = [self.storyboard instantiateViewControllerWithIdentifier:#"other"];
[self presentViewController:other animated:YES completion:nil];
OtherViewController.m
[self dismissViewControllerAnimated:YES completion:nil];
but when i dismiss it, the user starts from the beginning again. is there a way to save where the user is and continue from there?
You're presenting the new view controller as a modal. When you dismiss it, the previous view controller should be uncovered in it's previous state.
If it's not, then you need to look at the logic of your ViewController class.
You want your one time setup code in your viewDidLoad method. If you have code in your viewWillAppear:animated method, or your viewDidAppear:animated method that resets the state of your view controller then that is the problem.
I have a UINavigationController, in which I push a view controller with a UIModalPresentationPageSheet presentation style.
From within this page sheet's view controller, I present a view controller with UIModalPresentationFormSheet style.
When the user hits a Done button the the form sheet, I want to close out the form sheet and the page sheet.
In the action on the Done button:
-(IBAction)onDone:(id)sender
{
if(self->delegate && [self->delegate respondsToSelector:self->actionSelector])
{
[self->delegate performSelector:self->actionSelector withObject:[NSString stringWithString:self.textView.text]];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
The delegate is the page sheet's view controller, and in the selector, I dismiss the page sheet:
[self dismissViewControllerAnimated:YES completion:nil];
When I run it, I get:
Warning: Attempt to dismiss from view controller <UINavigationController: 0xa9381d0> while a presentation or dismiss is in progress!
I can see why this is happening - because the selector is called before the form view is dismissed, but I don't know the best way around this.
I have tried removing the dismiss in onDone, and call dismiss for both in the selector call (with animated:NO for the form sheet), and it seems to function, but I don't know if this is the way that I should approach fixing it.
Try just calling dismissViewControllerAnimated:completion: on the page sheet. According to Apple's docs:
"If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack."
If that's not exactly the behavior you want, then you should use the completion handler argument in dismissViewControllerAnimated:completion: to pass in a block, then dismiss the other view controller from the completion handler, eg:
[formSheetViewController dismissViewControllerAnimated:YES completion:^{
[pageSheetViewController dismissViewControllerAnimated:YES competion:nil];
}
Although really, I think just dismissing the page sheet should do the trick for you. It's still good to understand how completion handlers work. It lets you do some work after the operation is done--very handy.
I presented a view controller using presentModalViewController:, now how to close/dismiss it?
For iOS6 use this code
[self dismissViewControllerAnimated:YES completion:Nil];
instead of
[self dismissModalViewControllerAnimated:YES];
This may help you.
From the controller presented modally:
[self dismissModalViewControllerAnimated:YES]
You have two choices, both involves using dismissModalViewController.
The preferred way is to use delegation and tell the view controller who was responsible for presenting the view to dismiss it. The other way is to have the view who was presented to dismiss itself (which actually asks the parent to dismiss it.)