I am facing strange issue regarding Present and Dismiss ViewController.
For e.g :-
I am at ViewController A then i push to B
So in Navigation Controller Stack we have [A,B]
Now if i present any view controller on B (Like MFMailComposeViewController)
Then after sending mail or deleting draft it dismiss the MFMailComposeViewController and it redirects to A instead of B.
I have researched regarding this but can't find any alternative.
if you have called Popviewcontroller method in didFinishWithResult method of MFMailComposeViewControllerDelegate in ViewControllerB, then it could be possible.
instead you avoid PopViewController method call in didFinishWithResult method call.
Hope this helps. Use it when you switch between A -> B.
```let storyboard = UIStoryboard(name: "Main", bundle: nil)
desiredViewController = storyboard.instantiateViewController(withIdentifier: "desiredViewController")
UIApplication.shared.delegate?.window??.rootViewController? = desiredViewController ```
try this to presented MFMailComposeViewController from B
self.navigationController?.present(MFMailComposeViewController, animated: true, completion: nil)
You might have used
self.present(MFMailComposeViewController, animated: true, completion: nil)
Hope this helps
Hello you can do it like this, when you dismiss after sending mail or deleting draft it dismiss the MFMailComposeViewController and after that you can check the ViewController_Identifier if it is 'A_Screen' then avoid it or escape it. Else if, it is 'B-Screen' then navigate to that view controller.
Use this logic to navigate as you want.
let targetView: String! = self.restorationIdentifier
if targetView == "A_Screen"{
//Do nothing
}
else{
let B_View = self.storyboard?.instantiateViewController(withIdentifier: "B_Screen") as! BViewController
self.navigationController?.pushViewController(B_View, animated: true)
}
Make sure, that you have set identifierID for your ViewControllers.
Hope it helps you.
Related
Hello I am pretty annoyed with this:
Originally, I had many segues in my storyboard. Each button at bottom of tool bar would segue to various view controllers. As you can imagine, that is a lot of segues for 6 different items on toolbar. After segueing, each action would call self.dismiss and everything would be ok.
Recently, I wanted to clean up the storyboard.
I created the function:
extension UIViewController {
func segue(StoryboardID: String) {
let popOverVC = UIStoryboard(name: "Main", bundle:
nil).instantiateViewController(identifier: StoryboardID)
popOverVC.modalPresentationStyle = UIModalPresentationStyle.fullScreen
popOverVC.modalTransitionStyle = .crossDissolve
self.dismiss(animated: false, completion: nil)
print("dismissed")
self.present(popOverVC, animated: false, completion: nil)
print("presented")
}
}
What I am seeing is that the dismiss dismisses the new view controller from appearing. It essentially goes back to my first view controller presented upon launch. I want to dismiss all view controllers so that I don't keep piling up my views.
Thanks
The problem is that you present your popOverVC from a view controller that is being dismissed, so your popOverVC will never be shown as its parent is being dismissed.
Not sure how your architecture is exactly but you would either need to use the delegate pattern to tell the parent when to segue, for example:
self.dismiss(animated: true) {
self.delegate?.didDismiss(viewController: self)
}
Or to use some trick to get the top most view controller to present your popOverVC after the current view has been dismissed, ex:
self.dismiss(animated: true) {
var topController: UIViewController = UIApplication.shared.windows.filter{$0.isKeyWindow}.first!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
topController.present(popOverVC, animated: true)
}
But I agree with #Paulw11, a UITabBarController seem like a much better option for what you're trying to do.
I have implemented two different UIViewControllers, that should replace each other based on server respond and user actions. For simplicity let's think that we have two UIViewControllers with button replace with another, that should trigger this replacement.
Now I need to do that replace part, but the problem is there is some delay between dismissing one screen and showing the other. I want to somehow get rid of it. I show UIViewController modally with present method.
I thought about making these two screen as views in xib-files, and one UIViewController that will be loading these xibs, adding them as subViews and replacing one subView with another when it needs it, but maybe there is a way to do that with two UIViewControllers?
Code that I use to present controller:
let vc = UIViewController1()
vc.modalPresentationStyle = .overFullScreen
self.present(vc, animated: false, completion: nil)
And to dismiss:
self.dismiss(animated: false, completion: nil)
you can add a container view and in that view you can simply add your desired controller as the child view controller
official doc reference.
another reference
Set the present method's "animate" parameter to be false
To Present
let vc = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
self.present(vc, animated: false, completion: nil)
To Dismiss
self.dismiss(animated: false, completion: nil)
First you send notification to parent class for present another 'viewController' and then dismiss current class
Note: Both present class method set animation false
I would like to process code when a ViewController is no longer visible due to presenting a new ViewController.
I cannot use ViewWillDisappear etc since the controller is not technically ever dismissed from the stack - you just can't see it.
What process can I use so that code runs when the controller is no longer visible (i.e. topmost) and when it becomes visible again?
EDIT:
Seems some confusion here - not sure why.
I have a viewcontroller.
I use the following code to present another controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navController = storyboard.instantiateViewControllerWithIdentifier("NavController") as! UINavigationController
let thisController = navController.viewControllers[0] as! MyController
self.presentViewController(navController, animated: true, completion: nil)
This controller does not trigger a viewWillDisappear on the previous controller since the previous view is not removed - just hidden.
I need to process code when this view is hidden (i.e. not visible) and, more importantly, process code when it becomes visible again.
When presenting a UIViewController if the presentation style has been set to UIModalPresentationOverCurrentContext it doesn't call the viewWillDisappear and related methods as the view never disappears or gets hidden.
A simple test to check if thats the case would be to set the NavController that you are using to have a clear background color. If you do this and present the NavController and you can still view the first UIViewController below your NavController content. Then you are using UIModalPresentationOverCurrentContext and that is why the viewDidDisappear isn't called.
Have a look at the answer referenced by Serghei Catraniuc (https://stackoverflow.com/a/30787112/4539192).
EDIT: This is in Swift 3, you can adjust your method accordingly if you're using an older version of Swift
If you won't be able to figure out why viewDidAppear and viewDidDisappear are not called, here's a workaround
protocol MyControllerDelegate {
func myControllerWillDismiss()
}
class MyController: UIViewController {
var delegate: MyControllerDelegate?
// your controller logic here
func dismiss() { // call this method when you want to dismiss your view controller
// inform delegate on dismiss that you're about to dismiss
delegate?.myControllerWillDismiss()
dismiss(animated: true, completion: nil)
}
}
class PresentingController: UIViewController, MyControllerDelegate {
func functionInWhichYouPresentMyController() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navController = storyboard.instantiateViewController(withIdentifier: "NavController") as! UINavigationController
let thisController = navController.viewControllers[0] as! MyController
thisController.delegate = self // assign self as delegate
present(navController, animated: true, completion: {
// place your code that you want executed when it disappears here
})
}
func myControllerWillDismiss() {
// this method will be called now when MyController will dismiss
// place your code that you want executed when it re-appears here
}
}
Firstly, thanks to Serghei for his time in helping work through this.
To clarify, both my potential presented controllers were set to Full Screen presentation style in the storyboard, however one was being set to Custom via a piece of pasted code dealing with the presentation. I can't find the error with the other.
However, if I force a presentation style of Full Screen as part of the presenting process then all is ok.
Hopefully my frustrating afternoon can help to save someone else's - always try to understand the implications and processes involved in pasted snippets.
I have a problem, where I have two view controllers A and B. View controller B has a map, with a route draw on it. I can move back and forwards between the two view controllers at the moment, but the B view controller is reset every time it loads. I think this is because I am using segues and it is creating a new instance of a View controller every time.
I have tried using the following code to solve this issue, but it is still not working. The views load correctly, but view controller B is still being reset
#IBAction func mapButton(sender: AnyObject){
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
What am I doing wrong and how can I fix it? I want view controller B to stay in the memory along with the map and the route, so when a user returns he doesn't have to enter all of the information again.
You should create a variable in your class of type UIViewController and change your code to the following:
#IBAction func mapButton(sender: AnyObject){
if yourVariable == nil {
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
yourVariable = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
}
self.presentViewController(yourVariable, animated: true, completion: nil)
}
That way you create the viewController one time, save it and if you want to open it again present the previously created one.
I've been trying to present and dismiss a view controller programmatically and I keep running into EXC issues.
What is the proper way to present and dismiss a view controller other than using:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("Popup") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
and self.dismissViewControllerAnimated(true, completion: nil)
?
So far the app crashes when i run the function: dismissViewControllerAnimated
Please help, thanks!
Apparently, I had a NSNotification listener in the ViewController which caused the crash.
What I did was take it out and re-did the ViewController to populate the View Controller via a method rather than use a method linked to a NSNotification Listener.