Reputation: 2212
I was looking for a way to dismiss all the modally presented viewControllers in a UINavigationController
hierarchically without knowing the name of them. so I ended up to the while loop as follow:
Swift
while(navigationController.topViewController != navigationController.presentedViewController) {
navigationController.presentedViewController?.dismiss(animated: true, completion: nil)
}
Objective-c
while(![self.navigationController.topViewController isEqual:self.navigationController.presentedViewController]) {
[self.navigationController.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
I want to dismiss all the presentedControllers
one by one till the presentedViewController
and topViewcontroller
become equal.
the problem is that the navVC.presentedViewController
doesn't changed even after dismissing.
It remains still the same even after dismissing and I end up to an infiniteLoop
.
Does anyone knows where is the problem?
Upvotes: 0
Views: 1229
Reputation: 475
I had a similar issue of deleting/dismissing existing/previous push notification when a new push notification arrives where different pictures are sent as a push notification. In my situation, using Swift 5, I wanted to delete/dismiss previous push notification and display a new push notification all by itself regardless whether the user acknowledged the previous notification or not (i.e. without user's acknowledgement).
I tried Kadian's recommendation with a minor change and it worked flawlessly.
Here is my NotificationDelegate.swift
import UIKit
import UserNotifications
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
defer { completionHandler() }
guard response.actionIdentifier == UNNotificationDefaultActionIdentifier else {return}
let payload = response.notification.request.content
let pn = payload.body
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: pn)
//***Below cmd will erase previous push alert***
self.window!.rootViewController?.dismiss(animated: false, completion: nil)
//Below cmd will display a newly received push notification
self.window!.rootViewController!.present(vc, animated: false)
}
}
Upvotes: 0
Reputation: 13734
In my case nothing works but:
func dismissToSelf(completion: (() -> Void)?) {
// Collecting presented
var presentedVCs: [UIViewController] = []
var vc: UIViewController? = presentedViewController
while vc != nil {
presentedVCs.append(vc!)
vc = vc?.presentedViewController
}
// Dismissing all but first
while presentedVCs.count > 1 {
presentedVCs.last?.dismiss(animated: false, completion: nil)
presentedVCs.removeLast()
}
// Dismissing first with animation and completion
presentedVCs.first?.dismiss(animated: true, completion: completion)
}
Upvotes: 2
Reputation: 2212
I've found the answer. I can dismiss all presentedViewControllers
on a navigationController by:
navigationController.dismiss(animated: true, completion: nil)
It keeps the topViewController
and dismiss all other modals.
Upvotes: 1
Reputation: 33
Glad to see you have found the answer, and I've done this by another way.
You can create a BaseViewController(actually lots of app do that), and defined a property like 'presentingController' in appdelegate that indicate the presenting ViewController, then in the viewWillAppear method, set the property so that it always indicate the top view controller.
-(void)viewWillAppear:(BOOL)animated{
AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
delegate.presentingController = self;
}
All the class inherited from BaseViewController will call it. When you want to dismiss all the controller, just loop as follow:
- (void)clickButton:(id)sender {
AppDelegate *delegate=(AppDelegate *)[[UIApplicationsharedApplication]delegate];
if (delegate.presentingController)
{
UIViewController *vc =self.presentingViewController;
if ( !vc.presentingViewController ) return;
while (vc.presentingViewController)
{
vc = vc.presentingViewController;
}
[vc dismissViewControllerAnimated:YEScompletion:^{
}];
}
}
Hope this will help you :)
Upvotes: 0
Reputation: 151
Please check this code
-(void)dismissModalStack {
UIViewController *vc = self.window.rootViewController;
while (vc.presentedViewController) {
vc = vc.presentedViewController;
[vc dismissViewControllerAnimated:false completion:nil];
}
}
Upvotes: 0
Reputation: 871
Not need to used self.navigationController.presentedViewController.
Might be help! my code is as follows: Objective-c
[self dismissViewControllerAnimated:YES completion:^{
}];
// Or using this
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
Upvotes: 0
Reputation: 654
Form your question I understood that you want to dismiss all view controllers above the root view controller. For that you can do it like this:
self.view.window!.rootViewController?.dismiss(animated: false, completion: nil)
Upvotes: 0