Present View Controller right after Dismissing View Controller with no animation - ios

I have a UIImagePickerController presented on screen. When I choose the photo I need to dismiss the PickerController then immediately present another PhotoEditController. Here is my code
picker.dismissViewControllerAnimated(false, completion: {
self.presentViewController(editPhotoVC, animated: false, completion: nil)
})
There is a 0.1s flash between dismissing old VC and presenting new VC so the presentingViewController (self) is shown. How do I avoid that in an elegant solution not hacking it through? Thanks

The standard way of implementation is to dismiss first view controller (VC) with animation and present second VC with animation.
However, depending on your view hierarchy, you could also have your second VC loaded first and then present first VC on top of it. With this simply dismissing first VC without animation should show underneath second VC without delay.
Third approach, as LLooggaann suggested, don't dismiss first VC and simply present second VC. Once done, dismiss the entire view controller hierarchy in one shot.

You could instantiate PhotoEditController's instance, then do something like this:
instance.willMoveToParentViewController(controllerThatPresentsPicker)
controllerThatPresentsPicker.addChildViewController(instance)
controllerThatPresentsPicker.view.insertSubview(instance.view, belowSubview: picker.view)
instance.didMoveToParentViewController(controllerThatPresentsPicker)
It looks a bit like a hack though

That is most probably because dismiss is sent to the VC that presented the picker and it dismisses the picker modal vc and executes the completion handler after attempting to present the parent VC which is itself.
one solution would be creating your own transition class, you can basically copy paste the code from here to do that

Related

Transition from one modal VC to another without delay swift

I have a basic scenario:
I present a VC modally using self.present(, animated:, completion:).
Sometimes due to interactions in this modal VC i need to close one modal and open another one.
So i do the following:
weak var presenter = self.presentingViewController
let newVc = UIViewController()
presenter?.dismiss(animated: true, completion: {
presenter?.present(newVc, animated: true, completion: nil)
})
This works but there is the annoying delay when switching the VC's when user sees the original presenter and can try to interact with it (to open other modals...).
I tried setting animated: false but that doesn't seem to work :/
I can't really switch to UINavigationController model for this because the modals i am presenting themselves are Page View Controllers and have the whole hierarchy of dependent views; the user is never going 'back'; so i'd really like to just present the new modal as quickly as possible...
Update My question is not about how to control or choose the animation. My questions is about having no delay between the modals.
The built-in view controller architecture that switches views with no transition is the tab bar controller. So just turn your view controller into a tab bar controller — with no visible tab bar! To change to the other view controller just change tabs (in code). The change is instant.
This screencast makes it clear that this works as described. We present a view controller (yellow). Then we switch back and forth between two view controllers (green and yellow) as the presented view controllers, instantly. Finally, we dismiss whichever one (green or yellow) is showing. I'm doing it all with simple buttons but that's just for the demo; obviously you could do this however you like. It's the architecture that's the important thing.
I can think only of solutions which would require you to handle the animations yourself
create custom modal transition using UIViewControllerTransitionCoordinator
add your controllers to container views as suggested by #muhammed-gül
present newVC over self and dismiss all presented controllers when you're done
And just a tip, you don't always need to wait for the dismiss completion closure, you can call this and it usually works, but still the underlying viewController is visible.
dismiss(animated: true)
present(newVC, animated: true)

View Controller not dismissing properly

I'm in the process of implementing a cancel button for one of my view controllers. This view controller can either be shown, or presented modally. The cancel button works fine when the view controller has been shown, but it is not having any effect when the VC has been presented modally. I have a line of code for my cancel button:
let isPresentingInAddRoutineMode = presentingViewController is UINavigationController
This line of code is supposed to distinguish whether the VC has been shown or presented. I got the line from the Apple development website. In the cancel function it then reads:
if isPresentingInAddRoutineMode {
dismiss(animated: true, completion: nil)
}
According to the website, the variable should be reading true as the VC has been presented modally (The segue in storyboard says present modally). I tried debugging to see if the boolean is returning true, but it is not. I'm very confused by this and would be very grateful if anyone had any ideas what I've done wrong here.
Thanks.
Perhaps this could be of use instead: isBeingPresented
From: https://developer.apple.com/documentation/uikit/uiviewcontroller/2097564-isbeingpresented

Initial View Controller from everywhere

I got an application with a navigation view controller as Initial View Controller. After loading the initial view controller, I set up a notification listener. The Notification can be posted everywhere in the app. I have some pushed vc's and also modally presented. My goal is to return to the initial vc and present a modal view controller from there if the notification is triggered but I have no Idea how to do that. Do I need to do this outside of the MainViewController?
Answer assumes rootViewController is UINavigationController as specified by OP in his question
You can achieve what you want using
(UIApplication.shared.keyWindow?.rootViewController as! UINavigationController).dismiss(animated: true) {
(UIApplication.shared.keyWindow?.rootViewController as! UINavigationController).popToRootViewController(animated: true)
}
Whats happening is pretty simple. Knowing that your initial viewCOntroller is always UINavigationController, initially check if you have anything presented on rootView controller, if yes dismiss it and in the completion block pop to rootViewController of your initial viewController.
Hope it helps

Dismiss presented view controller, after the presenting view controller has been released

I am working on some old code that I didn't write, and it's really not architected well...
The situation is that a view controller presents a custom view controller modally, however every 30 seconds the presenting view controller is recreated.
The issue here is that if the modal is on screen when this happens, then any effort to dismiss it results in odd behaviour (such as a white screen).
I have tried calling [self.presentedViewController dismissViewControllerAnimated]; on the newly recreated controller, but presentedViewController is nil as you would expect.
I have also tried keeping a weak reference to the modal view controller, then when the presenting VC is reloaded, setting this value to that of the old VC. This has allowed me to call self.customModalVC dismissViewControllerAnimated]; but this is causing the aforementioned white screen, perhaps because it's presenting VC is no longer in the stack?
Any and all suggestions appreciated.
Try passing the navigation controller to newly presented ViewController:
presentedVC.navigation = self.navigationController
Add this to newly created one for dismissing
self.dismiss(animated: false) {
_ = self.navigation?.popViewController(animated: true)
}

"Present Modally" does not show when another modal is already presented

In my iOS application, my VC is presenting a modal (A) via code.
However, when I already have another modal presented (B), this one is not showing at all.
However, when (A) is deinitted, I see that (B) also gets deinitted.
How can I make sure that (B) always gets shown, no matter what, and in front of all other modals?
performSegueWithIdentifier(SEGUES.SegueTabBarToBroadcast, sender: view )
My TabBarViewController is calling this segue. (The segue is modal according to storyboard).
The problem occurs when one of the view controllers in my TabBar presents a modal. Then, when I try to call performSegueWithIdentifier, the modal doesn't show (but yet deinits when I close the other modal).
I just want this modal to present NO MATTER WHAT. This modal should overlap all other modals.
I also tried this, but the problem persists:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let bvc = storyboard.instantiateViewControllerWithIdentifier("BroadcastViewController") as! BroadcastViewController
self.presentViewController( bvc , animated: true, completion: nil)
Presenting multiple view controllers as a modal is not good practice. If you want to present your vc no matter what, then you have to understand the hierarchy of your view controllers. Shortly, you can present view controller modally on the vc with view that has a window, and when you have already presented any vc modally, your view controller's view that has presented the vc does not have the window, thus can't present other view controller modally. Conclusion: you can present vc modally from the top-most vc. So, solution would be keeping reference to the top-most vc, and presenting the desired vc from that vc. Another solution would be adding vc's view directly to the main window of the app, but I would not recommend solving your problem that way. Hope, this helps.

Resources