Dismissing a Popover created by a segue on iOS 9 - ios

There are a lot of questions and answers on Stack Overflow about this but they are just valid for iOS 8 and before.
iOS 9 deprecated a lot of things and the answers on SO did not work anymore.
Said that, I am presenting a popover by performing a segue like this
[self performSegueWithIdentifier:#"myPopover" sender:self];
This segue is created between the current viewController and the viewController used by the popover. There is no button involved. The popover is anchored to a view.
The problem is that on prepareForSegue:identifier
[segue destinationViewController]
is a UIViewController and
[[segue destinationViewController] popoverPresentationController]
is the new UIPopoverPresentationController and this object does not offer a dismiss api anymore.
Instead, we are supposed to use
[self dismissViewControllerAnimated:YES completion:nil];
to dismiss the popover but this has no effect for me.
My situation is this: I have a popover with a text field. I want to dismiss the popover if the user hides the keyboard.
So I did this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
and then
- (void)keyboardWillHide:(NSNotification *)notification {
[self dismissViewControllerAnimated:YES completion:nil];
}
but this has no effect at all.
I have also tried to create an unwind segue inside the popover viewController and call that from the presenting view controller but that makes the app crash.

Just tried it and it all seems to work perfectly.
What is your view controller hierarchy (navigation controllers, etc.)?
Are you properly calling dismissViewControllerAnimated:completion: on the same view controller that presented the popover?
Make sure there isn't a mixup between child view controller and navigation controller.
You can also log the popover view controller's presentingViewController to check.

Related

How to dismiss multiple view controllers which have been presented not pushed?

Scenario:
I need to show 3 or more popups one after the other on button click in each popup. I have created a different viewcontroller and xib files for each popup. So for displaying each popup I have used presentViewController instead of pushViewController.
That is, I have used this:
[self presentPopupViewController:searchPopUpView animationType:0];
instead of
[self.navigationController pushViewController:searchPopUpView animated:YES];
For dismissing a popup, the following code has been written:
[self dismissPopupViewControllerWithanimationType:0];
Issue:
The popups are displaying perfectly, but the background gets darker and darker whenever a popup shows up. After all popups have been dismissed I have to finally click on the blank screen to remove those darker parts. How to overcome this issue?
I think you are using MJPopupViewController to show pop-up.
If it is so, Then try this.
Suppose there is a controllerA from which you want to show a pop-up controller popupControllerB.
Then in your controllerA add Notifications Observer
Code to write in controllerA :
// Add Notification Observer when your view initialise.
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(dismissPopup) name:#"DISMISS_POPUP" object:nil];
In viewWillDisappear remove the notifications observer
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
This method will be called when you Post-notification from your popupControllerB
-(void)dismissPopup {
[self dismissPopupViewControllerWithanimationType:MJPopupViewAnimationFade];
}
And In popupControllerB, Where you want to dismiss the Pop-up, write this code.
[[NSNotificationCenter defaultCenter] postNotificationName:#"DISMISS_POPUP" object:nil];
Above line of code will call a method written in your controllerA and dismiss the pop-up properly.
If you want to dismiss presented UIViewControllers you can use this code. I have used this approach to dismiss presentedViewControllers. It will dismiss all your presentedViewControllers on your rootViewController.
UIViewController* presVC = self.window.rootViewController;
while (presVC) {
UIViewController* temp = vc.presentingViewController;
if (!temp.presentedViewController) {
[vc dismissViewControllerAnimated:NO completion:^{}];
break;
}
vc = temp;
}

Dismissing view controllers all at once

I need to go back all the way to the view controller that presented the first navigation controller. However I haven't dismissed multiple controllers before at once, and when I've tried doing so, it doesn't work. It just goes to the first navigation controller instead of all the way to the one before it.
Here is my current code:
[(UINavigationController *)self.presentingViewController popViewControllerAnimated:NO];
[self dismissViewControllerAnimated:YES completion:nil];
I have a view controller which modally presents the first navigation controller. The first navigation controller screen is called Main View Controller. It then pushes to Login View Controller. Login View Controller does presentViewController to MenuViewController (UIViewController).
I need to get from MenuViewController all the way back to the view that presented the first navigation controller. Thanks.
Try this
UIViewController *vc = self;
while (vc.presentingViewController != nil) {
vc = vc.presentingViewController;
}
[vc dismissViewControllerAnimated:YES completion:nil];
One option would be to use NSNotifications.
You can add an observer in your first/root/initial UINavigationController subclass e.g.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(logout:)
name:#"LogoutNotification"
object:nil];
Then in your "logout:" method you have direct control over the initial UINavigationController rather than those further up the hierarchy.
You can then send an NSNotification from anywhere in the app in order to trigger the method.
e.g.
[[NSNotificationCenter defaultCenter] postNotificationName:#"LogoutNotification" object:self];

Dismissing view controller to reveal desired one on the backside

Suppose i have 3 view controllers. I initiate vc1 in vc0 and then vc2 in vc1. Now i want vc2 to be dismissed and after that only vc0 should be shown behind it. How's that possible? I read something about delegate declaration. But couldn't understand.
I have UISegmentcontrol where i'm displaying a controller from storyboard like - vc0 = [self.storyboard instantiateViewControllerWithIdentifier=#"vc0"]; and making it a subview of it [self.view addSubview:vc0.view]; Vc0 is a tableView, which has a detailcontroller to be presented. When i tap on a cell, it shows detailview, but actual segmentcontrol.view is lost when detailview is dismissed.
An example would be awesome.
PS: I'm not using segue for the viewControllers. Instead, i'm using presentModalViewController and dismissModalViewController.
In iOS 5 you need to do
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES]
As of iOS 6 dismissModalViewControllerAnimated: is deprecated.
You need to call
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{ // Do something on completion}]
//If you want to perform something while going through views or other wise keep completion to nil as shown in below code.
or
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
or
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];

iOS - Call delegate method on main view from popover inner (pushed) view?

I need to call a delegate method on my main view controller ('showDetails:') from a popover view's pushed view (embedded in navigation controller). This is all from a storyboard setup.
The hierarchy is: Main view -> Popover (menu tableview embedded in navigation controller)->Popover secondary View (pushed onto popover navigation controller)
I know how to setup a delegate on the popover using prepareForSegue, but not on an inner view.
How can I call a delegate method on the main view from an inner (pushed) view of a popover?
Here is how I setup the delegate on a popover main view:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segueSearchResults"]) {
//Dismiss User Popover
[self dismissUserPopover];
SearchResultsViewController *vc = segue.destinationViewController;
vc.searchDelegate = self;
self.searchPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
self.searchPopover.delegate = self;
}
}
Instead Delegate i prefer "NSNotificationCenter" in your case
Add an observer to your ViewController for some action in uiview
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveActionNotification:)
name:#"someActionNotification"
object:nil];
Post Notification from your pushed View in PopOverController
Post Notification and method in your Viewcontroller will be called
[[NSNotificationCenter defaultCenter] postNotificationName:#"someActionNotification" object:self];
At the end Dont forget to remove Observer.
[[NSNotificationCenter defaultCenter] removeObserver:#"someActionNotification"];
When you need to communicate between two view controllers which are far apart in the VC hierarchy, trying to reference one from the other so you can directly call methods on it doesn't work so well -- there's several levels of indirection in between, and it's very fragile if you change your VC hierarchy later.
Look into notifications (NSNotificationCenter) instead; you can have one VC "broadcast" info for another to respond to, regardless of where they are in your app.

Dismissing 2 ViewController consecutively

I try 2 ways to dismissed 2 viewcontrollers consecutively but only one of them got dismissed not the second one
method1
-(void) LoginDone:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL]; //previous viewcontroller
[self dismissViewControllerAnimated:YES completion:NULL]; //current viewcontroller
}
method2
-(void) LoginDone:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL];
[[NSNotificationCenter defaultCenter] postNotificationName:#"LoginDone2" object:nil];
}
-(void) LoginDone2:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
I need to find out a way to dismiss both the previous viewcontroller and current viewcontroller consecutively.
This is now an old question, but it seems to be exactly the problem I am having presently.
Here what I did:
[self.presentingViewController.presentingViewController
dismissViewControllerAnimated:YES completion:nil];
And it works for me. I hope it can be useful to someone.
By calling
[self dismissViewControllerAnimated:YES completion:NULL];
you are telling self to dismiss the view it presented. Telling twice the same self object to dismiss the view it presented, will not change the result. In other words self cannot represent the "current view" and the "previous view" at the same time as per your comment to the code. self is just a single controller representing a single view, either the current or the previous one.
To fix this, you should send the dismissViewControllerAnimated to self (that presented the top-most view, I assume) and to the other view controller object that presented the previous view.
In other words, I would expect something like this:
-(void) LoginDone:(NSNotification *)notif
{
[self dismissViewControllerAnimated:YES completion:NULL];
[self.previousController dismissViewControllerAnimated:YES completion:NULL];
}
Actually, you could send just one message to the second view controller and both views would be dismissed (source):
If you present several view controllers in succession, and thus build 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.
I know this is an old question but maybe somebody will look for solution on this issue so here it is:
-(void) closeModalViews
{
[previousVC dismissViewControllerAnimated:YES completion:^(void) {
[self dismissViewControllerAnimated:YES];
}];
}
I like JPetric's idea, but first you must dismiss the current view controller's view and only then can you dismiss the presenting view controller's view.
[self dismissViewControllerAnimated:NO completion:^(void) {
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}];
As far as I could understand you are trying something like below:
There are 2 view controllers.
You want both of them to be vanished.
Another controller comes in.
But the fact is only one controller is displayed, why you would need to dismiss 2 then?
You can use self.view.hidden=true; on the jumped viewcontrollers while animating back to the first viewcontroller. Using [self.presentingViewController dismiss...] is not working for me without hiding.

Resources