Set data in `prepareForSegue` with navigation controller
IosSwiftUinavigationcontrollerIos Problem Overview
I am developing an iOS application in Swift.
I want to send data from a view to an other one, using the prepareForSegue
function.
However, my target view is preceded by a navigation controller, so it doesn't work. How can I set data on the VC contained within the navigation controller?
Ios Solutions
Solution 1 - Ios
In prepareForSegue
access the target navigation controller, and then its top:
let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController
From the target controller you can access its view and pass data.
In old - now obsolete - versions of Swift and UIKit the code was slightly different:
let destinationNavigationController = segue.destinationViewController as UINavigationController
let targetController = destinationNavigationController.topViewController
Solution 2 - Ios
-
Prepare the segue in the SendViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "segueShowNavigation" { if let destVC = segue.destination as? UINavigationController, let targetController = destVC.topViewController as? ReceiveViewController { targetController.data = "hello from ReceiveVC !" } } }
-
Edit the identifier segue to "showNavigationController"
- In your ReceiveViewController add
this
var data : String = ""
override func viewDidLoad() {
super.viewDidLoad()
print("data from ReceiveViewController is \(data)")
}
Of course you can send any other type of data (int, Bool, JSON ...)
Solution 3 - Ios
Complete answer using optional binding
and Swift 3 & 4:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let navigationVC = segue.destination as? UINavigationController, let myViewController = navigationVC.topViewController as? MyViewControllerClass {
myViewController.yourProperty = myProperty
}
}
Solution 4 - Ios
Here is the answer for Swift 3:
let svc = segue.destination as? UINavigationController
let controller: MyController = svc?.topViewController as! MyController
controller.myProperty = "Hi there"
Solution 5 - Ios
A one liner in Swift 3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination.childViewControllers[0] as? FooController {
vc.variable = localvariable
}
}
Solution 6 - Ios
In Swift 5
If you must not only segue from a SourceViewController to a DestinationViewController embedded in a UINavigationController, but also to a new Storyboard also, then do the following...
-
Place a "Storyboard Reference" object from your Object Library next to your source ViewController in Interface Builder, and then drag a segue to it (from a button on the SourceViewController view, for instance). Name the segue identifier "ToOtherStoryboard", for example.
-
Go to NavigationViewController and give it a Storyboard ID using the Identity Inspector. "DestinationNavVC" would do.
-
Click the Storyboard Reference icon you created in step 1, and in its attribute inspector's 'Referenced ID' field, enter the Storyboard ID you wrote for the UINavigationController in step 2. This creates the segue from source to the DestinationViewController no matter what you write in source file of the source ViewController. This is because seguing to a NaviationController will automatically show the root ViewController (the first one) of the UINavigationController.
-
(OPTIONAL) If you need to attach data along with your segue and send it to properties within the DestinationViewController, you would write the following code inside a Prepare-For-Segue method in your SourceViewController file:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "ToOtherStoryboard" { let destinationNavVC = segue.destination as! UINavigationController let destinationVC = destinationNavVC.topController as! DestinationViewController destinationVC.name = nameTextField.text // for example destinationVC.occupation = occupationTextField.text } }
You do not NEED to have a PrepareForSegue if you're simply trying to move from one ViewController to another, the methods above will work (w/o step 3)
-
In your IBAction Outlet method for your button you used to initiate the segue, you would write:
performSegue(withIdentifer: "ToOtherStoryboard", sender: self)
Solution 7 - Ios
Set the identifier name in the segue arrow property in order to use in the the performeSegue.
Like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc: ProfileViewController = segue.destination as? ProfileViewController {
//do any setting to the next screen
}
}
and then:
performSegue(withIdentifier: "yourIdentifierOfViewProfile", sender: indexPath.row)
I hope it helps.
Solution 8 - Ios
It's a good idea to skip the check for UINavigationController
as there may be multiple segues
that use a navigationController
and so will go into that check for every segue
that uses a navigationController
. A better way is to check the first viewController
of the children
and cast it as the viewController
you are looking for.
if let destVC = segue.destination.children.first as? MyViewController {
destVC.hideBottomBar = true
}