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.
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 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.
I have a view controller that shows the details of an object. On this view controller is an "edit" button which shows modally the edition view controller. When I try to dismiss the modally presented view (edit view controller) :
self.dismissViewControllerAnimated(true, completion: nil)
I get the following error and it's presenting my initial viewController instead :
Warning: Attempt to present ≤Deevent.MyEventsVC: 0x7f99b70160a0≥ on ≤Deevent.EventCreationVC: 0x7f99b7238690≥ whose view is not in the window hierarchy!
So what I've tried was to set the root view controller of my view to the view I wanted to go back and present it in the completition of my dismiss. It's working well, but my application is in a Tabbar Controller and now it's not in it anymore. Same for the navigation controller.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MyEventsStoryboard") as! MyEventsVC
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
appDelegate.window?.rootViewController = vc
self.dismissViewControllerAnimated(false, completion: {
self.presentViewController(vc, animated: true, completion: nil)
})
Is there an other approach for presenting viewControllers after dismiss without leaving the Tabbar controller ?
Thanks
Since you are trying to present the new view controller by calling self.presentViewController after you dismiss self, you get the error. I can offer you a solution if you are using a navigation controller.
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.