Using @IBSegueAction with UINavigationController
To achieve the result which you want I recreated a simple project which I will link on my GitHub.
To start off, you need to get rid of the segue you have created to your Navigation controller and recreate it.
Next select present Modally and name your segue with an identifier
Next you need to define the IBSegueAction in your first ViewController
ViewController.swift
import UIKit
class ViewController: UITableViewController {
let persons = ["Robert", "Peter", "Dave"]
var selectedPerson = 0
override func viewDidLoad() {
super.viewDidLoad()
}
@IBSegueAction
private func showPerson(coder: NSCoder, sender: Any?, segueIdentifier: String?)
-> PersonViewController? {
return PersonViewController(coder: coder, personDetails: persons[selectedPerson])
}
//MARK:- TableView Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return persons.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "personCell", for: indexPath)
cell.textLabel?.text = persons[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedPerson = indexPath.row
performSegue(withIdentifier: "ShowPerson", sender: self)
}
}
Then add the implementation of init?(coder: NSCoder, personDetails: String)
in the PersonViewController as follows.
Xcode will yell that you need to implement required init?(coder: NSCoder)
Just tap fix.
PersonViewController.swift
import UIKit
class PersonViewController: UIViewController {
//Your data passed in below as non optional constant
let personDetails: String
//The received data gets initialized below
init?(coder: NSCoder, personDetails: String) {
self.personDetails = personDetails
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@IBOutlet weak var personLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
personLabel.text = personDetails
}
}
The next step is to select the ViewController's top part in the storyboard so you can see the three icons.
Following that, you have to select the Segue which goes out from the second UINavigationController to your destination ViewController here PersonViewController and drag back from the segue to the first yellow icon of the ViewController you want to send information from like on the screenshot below. Xcode will automatically recognize the IBSegueAction's name which you created in code.
That's it.
You should get a result like this once you tap any of the cells in the first View Controller
Here is the sample project GitHub
I also found more information about IBSegueAction here
I had the same problem but managed to get it working. Instead of setting your segue action selector on your Show Detail segue, set it on Navigation Controller's Relationship Segue, as in the following screenshot: