Perform unwind segue programmatically - ios

Currently I have the following storyboard:
UITableViewController -> Segue -> UINavigationController -> Relationship -> UITableViewController
In the last UITableViewController I added a back button with the code below:
navigationItem.setLeftBarButtonItem(UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "unwind"), animated: true)
let attributes = [NSFontAttributeName: UIFont.fontAwesomeOfSize(30), NSForegroundColorAttributeName: Constants.InterfaceColors.firstHighlightColor] as Dictionary!
let unwindNavigationItem = navigationItem.leftBarButtonItem! as UIBarButtonItem
unwindNavigationItem.setTitleTextAttributes(attributes, forState: .Normal)
unwindNavigationItem.title = String.fontAwesomeIconWithName(FontAwesome.AngleLeft)
As far as I read I have to connect the File's owner to the exit in the storyboard. I found out, that this is only possible if you have an action in your controller code like the one below.
#IBAction func unwindToWeekOverview(segue: UIStoryboardSegue) {
NSLog("unwind to week overview")
dismissViewControllerAnimated(true, completion: nil)
}
Since I don't now how to directly connect the action of a button to my unwind action I added the unwind function.
func unwind() {
performSegueWithIdentifier("UnwindToWeekOverview", sender: self)
}
When I now click the back button, the unwind function is called, but not the segue.
What am I missing?

Have a look at this link. It is by MIKE WOELMER and he explains it very clearly.
https://spin.atomicobject.com/2014/10/25/ios-unwind-segues/
So first of all, you need to create an IBAction in a destination view controller, something like this:
#IBAction func goBack(segue: UIStoryboardSegue) {
print("go back")
Then you just need to connect (control drag) from your button to Exit outlet. In the pop up you will see the function added previously, just select it and it should work.

Related

In navigation controler how to implement a add button opens a new view controller

I am new to swift , I have a very simple question. I implement a navigation controller with two items at top like this
I did this by adding a navigation controller to the project and then adding this lines of code in to the viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.title = ""
self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.navigationItem.setLeftBarButton(UIBarButtonItem(barButtonSystemItem: .add, target: self, action: Selector(("barButtonItemClicked:"))), animated: true)
}
now my question is about how to open a new view controller I mean a new page after clicks on plus (+) button at the navigation bar. I searched a lot but did not find any exact thing relate to this. Appreciate you if possible help me. thank you
Your code should be like this one:
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, style: .plain, target: self, action: #selector(performToVC))
#objc func performToVC() {
performSegue(withIdentifier: "vc", sender: self)
}
Here is code for Push TO OTherView Controller
#objc func PoushTOHistoryVC() {
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "HistoryViewController") as! HistoryViewController
self.navigationController?.pushViewController(secondViewController, animated: true)
}
here is Button for Add
self.navigationItem.setLeftBarButton(UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(PoushTOHistoryVC)), animated: true)
you need to add HistoryViewControlle to Stroyboard ViewController HistoryViewControlle and Don't forget
First you have to create new view controller which you have to open on that plus (+) button at the navigation bar. After creating new view controller you have to press and hold the control key on the keyboard and the click on the (+) button at the navigation bar and drag it to the new view controller and then release the click button image for reference, then it will show you a pop up with options such as show, show details etcimage for reference, select show option.

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

Linking up a button through a segue when using material.io

Im a beginner in swift and I am creating a login screen using Material.io in Swift and my UI looks like this .
However i dont see anything on my main.storyboard
I am used to creating a segue manually and then using
performSegue(withIdentifier: <#T##String#>, sender: <#T##Any?#>)
to use the segue but now since i dont see the button i'm unable to use the segue on clicking the 2 buttons Login and Register.
Also, usually from main.storyboard you have an IBOutlet or IBAction block to trigger certain features such as do something on a button click.
How does that work when you use MDCButton for instance. How do you link up the button to an action such as trigger a segue or update a text field.
Thank you.
I have declared my button like this
let nextButton: MDCButton = {
let nextButton = MDCButton()
let containerScheme = MDCContainerScheme()
nextButton.applyTextTheme(withScheme: containerScheme)
nextButton.setTitleColor(.white, for: .normal)
nextButton.translatesAutoresizingMaskIntoConstraints = false
nextButton.setTitle("CREATE NEW ACCOUNT", for: .normal)
nextButton.addTarget(self, action: #selector(didTapNext(sender:)), for: .touchUpInside)
return nextButton
}()
And i am calling it like this
#objc func didTapNext(sender: Any) {
self.performSegue(withIdentifier: "toRegistration", sender: self)
self.dismiss(animated: true, completion: nil)
}
I have a segue linking the 2 view controllers.
I can't see your code and don't have enough rep to comment, but it looks like you are building your view programmatically. To see when the button receives touchUp as you would from an outlet, you need to add a target. Try something like this:
func functionWhereYouCreateTheButton() { (PROBABLY YOUR VIEW DID LOAD)
let loginButton = UIButton()...
...
...
...
loginButton.addTarget(self, action: #selector(self.buttonTapped), for: .touchUpInside)
}
func buttonTapped() {
self.performSegue(withIdentifier: "SEGUEID", sender: self)
}

Two ViewControllers unwind issue

I have three View Controllers and want to go back from the third to the first on button click. I do the following:
Add the target to my button: doneButton.addTarget(self, action: #selector(ThirdViewController.doneButtonPressed(_:)), for: .touchUpInside)
Create the action in the first controller: #IBAction func unwindFromNewSubscription(segue: UIStoryboardSegue) {
}
Create the unwind segue linking it to the action from #2 in the storyboard and set the "chageFromNewToMain" identifier
Create the action for my button in the third controller: #IBAction func doneButtonPressed(_ sender:UIButton!) {
print("DONE BUTTON PRESSED")
performSegue(withIdentifier: "changeFromNewToMain", sender: self)
}
And it works, BUT when I tap the button in V3 it instantly disappears and I see the animation: V2 slides down, so finally I can see the V1. But I want to animate the V3 to slide down instead of disappearing to see V1 after that. Any ideas how to fix that?
(V1, V2, V3 - View Controller 1, 2, 3)
Try to use presentingViewController?.dismiss(animated: true, completion: nil) inside your #IBAction func doneButtonPressed(_ sender:UIButton!) action instead of calling performSegue(withIdentifier: "changeFromNewToMain", sender: self).

Programmatically go back to previous ViewController in Swift

I send the user over to a page on a button click. This page is a UITableViewController.
Now if the user taps on a cell, I would like to push him back to the previous page.
I thought about something like self.performSegue("back").... but this seems to be a bad idea.
What is the correct way to do it?
Swift 3:
If you want to go back to the previous view controller
_ = navigationController?.popViewController(animated: true)
If you want to go back to the root view controller
_ = navigationController?.popToRootViewController(animated: true)
If you are not using a navigation controller then pls use the below code.
self.dismiss(animated: true, completion: nil)
animation value you can set according to your requirement.
Swift 3, Swift 4
if movetoroot {
navigationController?.popToRootViewController(animated: true)
} else {
navigationController?.popViewController(animated: true)
}
navigationController is optional because there might not be one.
Swift 3
I might be late in the answer but for swift 3 you can do it this way:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "< Back", style: .plain, target: self, action: #selector(backAction))
// Do any additional setup if required.
}
func backAction(){
//print("Back Button Clicked")
dismiss(animated: true, completion: nil)
}
Swift 4
there's two ways to return/back to the previous ViewController :
First case : if you used : self.navigationController?.pushViewController(yourViewController, animated: true)
in this case you need to use self.navigationController?.popViewController(animated: true)
Second case : if you used : self.present(yourViewController, animated: true, completion: nil)
in this case you need to use self.dismiss(animated: true, completion: nil)
In the first case , be sure that you embedded your ViewController to a navigationController in your storyboard
swift 5 and above
case 1 : using with Navigation controller
Back to the previous view controller
self.navigationController?.popViewController(animated: true)
Back to the root view controller
self.navigationController?.popToRootViewController(animated: true)
case 2 : using with present view controller
self.dismiss(animated: true, completion: nil)
In the case where you presented a UIViewController from within a UIViewController i.e...
// Main View Controller
self.present(otherViewController, animated: true)
Simply call the dismiss function:
// Other View Controller
self.dismiss(animated: true)
If Segue is Kind of 'Show' or 'Push' then You can invoke "popViewController(animated: Bool)" on Instance of UINavigationController. Or if segue is kind of "present" then call "dismiss(animated: Bool, completion: (() -> Void)?)" with instance of UIViewController
for swift 3
you just need to write the following line of code
_ = navigationController?.popViewController(animated: true)
This one works for me (Swift UI)
struct DetailView: View {
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
VStack {
Text("This is the detail view")
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Back")
}
}
}
}
Try this:
for the previous view use this:
navigationController?.popViewController(animated: true)
pop to root use this code:
navigationController?.popToRootViewController(animated: true)
Swift 4.0 Xcode 10.0 with a TabViewController as last view
If your last ViewController is embebed in a TabViewController the below code will send you to the root...
navigationController?.popToRootViewController(animated: true)
navigationController?.popViewController(animated: true)
But If you really want to go back to the last view (That could be Tab1, Tab2 or Tab3 view..)you have to write the below code:
_ = self.navigationController?.popViewController(animated: true)
This works for me, i was using a view after one of my TabView :)
For questions regarding how to embed your viewController to a navigationController in the storyboard:
Open your storyboard where your different viewController are located
Tap the viewController you would like your navigation controller to start from
On the top of Xcode, tap "Editor"
-> Tap embed in
-> Tap "Navigation Controller
I would like to suggest another approach to this problem. Instead of using the navigation controller to pop a view controller, use unwind segues. This solution has a few, but really important, advantages:
The origin controller can go back to any other destination controller (not just the previous one) without knowing anything about the destination.
Push and pop segues are defined in storyboard, so no navigation code in your view controllers.
You can find more details in Unwind Segues Step-by-Step. The how to is better explained in the former link, including how to send data back, but here I will make a brief explanation.
1) Go to the destination (not the origin) view controller and add an unwind segue:
#IBAction func unwindToContact(_ unwindSegue: UIStoryboardSegue) {
//let sourceViewController = unwindSegue.source
// Use data from the view controller which initiated the unwind segue
}
2) CTRL drag from the view controller itself to the exit icon in the origin view controller:
3) Select the unwind function you just created a few moments ago:
4) Select the unwind segue and give it a name:
5) Go to any place of the origin view controller and call the unwind segue:
performSegue(withIdentifier: "unwindToContact", sender: self)
I have found this approach payoffs a lot when your navigation starts to get complicated.
I hope this helps someone.
I did it like this
func showAlert() {
let alert = UIAlertController(title: "Thanks!", message: "We'll get back to you as soon as posible.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
self.dismissView()
}))
self.present(alert, animated: true)
}
func dismissView() {
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
}
If you want to close previous two view controllers just call popViewController two times like this way:
self.navigationController?.popViewController(animated: true)
self.navigationController?.popViewController(animated: true)
I can redirect to root page by writing code in "viewDidDisappear" of navigated controller,
override func viewDidDisappear(_ animated: Bool) {
self.navigationController?.popToRootViewController(animated: true)
}

Resources