简体   繁体   中英

Swift : prepareForSegue with navigation controller

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 do this please ?

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
  1. 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 !" } } }
  2. Edit the identifier segue to "showNavigationController"

截屏

  1. 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 ...)

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
    }
}

Here is the answer for Swift 3:

let svc = segue.destination as? UINavigationController

let controller: MyController = svc?.topViewController as! MyController
controller.myProperty = "Hi there"

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
  }
}

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...

  1. 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.

  2. Go to NavigationViewController and give it a Storyboard ID using the Identity Inspector. "DestinationNavVC" would do.

  3. 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.

  4. (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)

  5. In your IBAction Outlet method for your button you used to initiate the segue, you would write:

     performSegue(withIdentifer: "ToOtherStoryboard", sender: self)

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.

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM