iOS Swift 4 Restart Navigation controller - ios

My storyboard looks like this:
Navigation Controller -> StepOne -> StepTwo -> StepThree
StepOne has a Segue Show to StepTwo etc.
In StepOne I open StepTwo on Button click like this:
#IBAction func next(_ sender: UIButton) {
self.performSegue(withIdentifier: "oneToTwo", sender: self)
}
In StepTwo I open StepThree the same way.
Now In my last StepThree I want to restart at StepOne :
#IBAction func end_click(_ sender: UIButton) {
self.navigationController?.popToRootViewController(animated: false)
}
This works fine.
The problem is that all the UI elements are still filled out from the first run. Of course I could clear all values before I navigate in each controller but this doesn't seem to be good practice.
Is there a way to tell NavigationController to use new instances of its ViewController s ?

I guess you can simply dismiss the root view controller of navigation controller and present it again.

You need
// this inside end_click
let vc = self.storyboard!.instantiateViewController(withIdentifier:"StepOneId")
self.navigationController!.setViewControllers([vc], animated: true)

Related

Swift unwind modal

I'm working on an app where I have an error page displayed incase there is a network problem. The app has several storyboards, and this can happen anywhere.
func displayErrorPage(errorCode: ErrorCode) -> Void {
if !isDisplayingError {
DispatchQueue.main.async {
self.isDisplayingError = true
let storyboard = UIStoryboard(name: "alert", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "AlertScreen") as! AlertVC
controller.errorCode = errorCode
UIApplication.shared.topViewController?.present(controller, animated: true, completion: nil)
}
}
}
I would like to use unwind to dismiss it, to clear out any views and get back to the home page. I have used this in the alert view to close, but sometimes doesn't work.
#IBAction func closeBtn(_ sender: Any) {
flowError = true
NetworkManager.shared().isDisplayingError = false
performSegue(withIdentifier: "unwindToSH", sender: self)
}
Anyone with some pointers?
Create the unwind segue IBAction in the view controller you want to unwind to. 
Perhaps in your case it is HomeViewController. Add this code inside your HomeViewController
#IBAction func unwindToHomeVC(segue: UIStoryboardSegue) {}
Wire up the unwind segue - Control drag from AlertVC’s ViewController icon to exit icon in the storyboard choose the unwind segue action (unwindToHomeVC) that was created in step 1 from the list of IBActions.
Specify a segue Identifier - specify its identifier in the Attributes Inspector of the Utilities Pane. Ex: “unwindToHomeVC”
Trigger unwind segue programmatically - trigger that in the appropriate place. In your case close button action
self.performSegue(withIdentifier: "unwindToMenu", sender: self)
It will work even if you work with multiple storyboard as well, if your setup is right. I hope that this one would help you.
Thanks

How to perform segue with navigation controller?

I just want to perform segue with a back button on top.
#IBAction func onFirst(_ sender: UIButton) {
performSegue(withIdentifier: "firstSegue", sender: self)
}
#IBAction func onSecond(_ sender: UIButton) {
performSegue(withIdentifier: "secondSegue", sender: self)
}
Let's say you have two view controllers, ViewControllerOne and ViewControllerTwo.
You could do that programmatically or using storyboards.
Since you seem to be using #IBOutlet I will assume you want to do it using storyboards.
First open up your Main.storyboard and make sure that ViewControllerOne (the controller you want to segue from) is embedded in a Navigation Controller.
If it's not, you can do that by clicking on your View Controller, then click on Editor in the top menu bar, go to Embed In and select Navigation Controller.
Then you can create a segue using the Interface Builder by doing control + click on the little yellow icon at the top of ViewControllerOne (not the Navigation Controller) & drag to ViewControllerTwo in the Interface Builder.
Now click on the segue that just got created, and type an identifier of your choice in the Attributes Inspector.
Then in your ViewControllerOne class, you can just perform the segue using the #IBOutlet as you mentioned :
#IBAction func onFirst(_ sender: UIButton) {
performSegue(withIdentifier: "your_segue_identifier", sender: self)
}
Just make sure that the segue identifiers match, and everything should be fine :)
You need redefine target and action for your current navigation item
self.navigationItem.leftBarButtonItem?.target = self
self.navigationItem.leftBarButtonItem?.action = #selector(self.onFirst(_:))

how to make a unwindsegue to viewcontroller before a navigation controller

i have a project where initial viewcontroller does not have a navigation controller a loguin windows after that i have a navigatino controller to the main view. so when I tap on close session i make a segue to loguin windows but that does not destroy any windows opened in previous, so I google for a solution an i show a unwindsegue to main viewviewcontroller but always the initial view controller is behind a navigation controller so my real question is is a valid approach to make
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
self.performSegue(withIdentifier: "goLogin", sender: nil)
}
You need change sender value nil to self value:
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
self.performSegue(withIdentifier: "goLogin", sender: self)
}

Swift back button segue

I have a navigation tableview controller Calculator and that goes to AddActiveIngredients which is where I add everything in for the calculator.
I have the segue method backButton in Calculator and in AddActiveIngredients I have click dragged the segue from the controller to exit and selected the segue in the Calculator class.
The segue identifier is also backButton but it's not doing anything.
I've tried this code to try and trigger the segue manually but that's not working. Am I missing something so simple?
override func didMoveToParentViewController(parent: UIViewController?) {
if (!(parent?.isEqual(self.parentViewController) ?? false)) {
print("Back Button Pressed!")
self.performSegueWithIdentifier("backButton", sender: self)
}
}
It sounds like you just want to remove the AddActiveIngredients from the stack. If so, you just need to call a function to dismiss it.
func dismissVC() {
dismissViewControllerAnimated(true, completion: nil)
}
You can put that in a button tap or something else. It'll work with Show and Modal segues. Unwinding may be overkill for what you're doing.
Hope it helps!
To use the Exit icon you need not create a segue at all.
All you have to do is add a method in the ViewController to which you want to unwind to and add a method with the signature:
#IBAction func myUnwindAction(segue: UIStoryboardSegue) {
// do stuff
}
Remember, you have to add this method in the target ViewController
When you Control-Drag from a button to the Exit icon, this method will now show up.
When you now click the button, the current ViewController will be popped and the action method in the target will be called.
Hope this helps.
with Swift 5 you can use Dismiss function
#IBAction func dismissViewController(_ sender: Any) {
//Go back to previous controller
dismiss(animated: true, completion: nil)
}

Show Segue uses the wrong presentingViewController, and causes wrong navigation

I am trying to fix up an edit segue (show in IB) where I can click the 'Edit report details' button on the toolbar and it will Show Segue towards the 'Configure Report' View controller.
However, if I click cancel, it goes all the way back to my login screen, because presentingViewController is a UINavigationController, even though it shouldn't be.
Here's the story board. http://i.imgur.com/DK4HhpO.png
Any ideas?
// MARK: Navigation
#IBAction func cancel(sender: UIBarButtonItem) {
// Depending on style of presentation (modal or push presentation), this view controller needs to be dismissed in two different ways.
let isPresentingInAddItemMode = presentingViewController is UINavigationController
if isPresentingInAddItemMode {
dismissViewControllerAnimated(true, completion: nil)
}
else {
// In this mode (push presentation), we need to pop the view controller to get rid of it, rather than dismissing
navigationController!.popViewControllerAnimated(true)
}
}
This is all I do in my code and it works.
#IBAction func cancel(sender: AnyObject) {
self.navigationController?.popViewControllerAnimated(true)
}
How ever you may need to check for which segue identifier sent you first.
#IBAction func cancel(sender: AnyObject) {
if (segue.identifier == "Edit") {
self.navigationController?.popViewControllerAnimated(true)
} else if (segue.identifier == "Add") {
self.navigationController?.popViewControllerAnimated(true)
}
This way it knows which one to follow. It also may depend on how you are segue to the view in the first place.

Resources