使用导航控制器在 `prepareForSegue` 中设置数据

Set data in `prepareForSegue` with navigation controller

我正在 Swift 开发一个 iOS 应用程序。

我想使用 prepareForSegue 函数将数据从一个视图发送到另一个视图。

但是,我的目标视图前面有一个导航控制器,所以它不起作用。如何在导航控制器中包含的 VC 上设置数据?

prepareForSegue访问目标导航控制器,然后是其顶部:

let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController

您可以从目标控制器访问其视图并传递数据。

在 Swift 和 UIKit 的旧版本(现已过时)中,代码略有不同:

let destinationNavigationController = segue.destinationViewController as UINavigationController
let targetController = destinationNavigationController.topViewController
  1. 在 SendViewController 中准备 segue

    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. 将标识符 segue 编辑为 "showNavigationController"

  1. 在你的 ReceiveViewController 中添加

这个

var data : String = ""

override func viewDidLoad() {
    super.viewDidLoad()
    print("data from ReceiveViewController is \(data)")
}

当然你可以发送任何其他类型的数据(int、Bool、JSON ...)

这是 Swift 3 的答案:

let svc = segue.destination as? UINavigationController

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

使用 optional binding 和 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
    }
}

Swift 3:

中的一个班轮
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  if let vc = segue.destination.childViewControllers[0] as? FooController {
    vc.variable = localvariable
  }
}

在Swift5

如果您不仅必须从 SourceViewController 转到 UINavigationController 中嵌入的 DestinationViewController,而且还要转到新的 Storyboard,那么请执行以下操作...

  1. 在 Interface Builder 中将对象库中的 "Storyboard Reference" 对象放置在源 ViewController 旁边,然后将一个 segue 拖到它上面(从 SourceViewController 查看,例如)。例如,将 segue 标识符命名为 "ToOtherStoryboard"。

  2. 转到 NavigationViewController 并使用 Identity Inspector 为其指定 Storyboard ID。 "DestinationNavVC" 可以。

  3. 单击您在第 1 步中创建的 Storyboard Reference 图标,并在其属性检查器的 'Referenced ID' 字段中,输入您在第 2 步中为 UINavigationController 编写的 Storyboard ID。这将创建 segue从源到目标ViewController,无论你在源ViewController的源文件中写什么。这是因为转到 NaviationController 会自动显示 UINavigationController 的根 ViewController(第一个)。

  4. (可选)如果您需要将数据与您的 segue 一起附加并将其发送到 DestinationViewController 中的属性,您可以在 Prepare-For-Segue 中编写以下代码SourceViewController 文件中的方法:

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

    如果您只是想从一个 ViewController 移动到另一个,则不需要 PrepareForSegue,上面的方法将起作用(w/o 第 3 步)

  5. 在您用于启动 segue 的按钮的 IBAction Outlet 方法中,您可以这样写:

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

在segue箭头中设置标识符名称属性以便在performeSegue中使用。

像这样:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if let vc: ProfileViewController = segue.destination as? ProfileViewController {

        //do any setting to the next screen

    }

}

然后:

    performSegue(withIdentifier: "yourIdentifierOfViewProfile", sender: indexPath.row)

希望对您有所帮助。

跳过 UINavigationController 的检查是个好主意,因为可能有多个 segues 使用 navigationController,因此将对每个 segue 进行检查] 使用 navigationController。更好的方法是检查 children 的第一个 viewController 并将其转换为您要查找的 viewController

if let destVC = segue.destination.children.first as? MyViewController {
    destVC.hideBottomBar = true
}