【问题标题】:Swift 3 - Prepare SegueSwift 3 - 准备 Segue
【发布时间】:2016-11-08 01:55:35
【问题描述】:

我的故事板中有 3 个场景。我的初始视图控制器是一个导航控制器,然后有一个关系根视图控制器到 UI 视图控制器(视图控制器 a),然后我有一个从视图控制器中的按钮到第三个视图控制器(视图控制器 b)的推送场景。我已经给 push segue 一个标识符。现在我正在尝试在第二个视图控制器(视图控制器 a)中准备我的 segue,如下所示:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "HistorySegue" {
            if let viewController = segue.destination as? HistoryController {
                viewController.detailItem = barcodeInt as AnyObject
            }
        }
    }

但是,当我运行此代码并按下控制器 a 中的按钮时,出现以下错误:

致命错误:尝试桥接包含 nil 的隐式展开的可选项

我做错了什么?

【问题讨论】:

  • barcodeInt 是什么?更多细节,请。
  • detailItembarcodeInt的类型是什么?

标签: ios swift swift3


【解决方案1】:

用下面的代码替换你的代码,至少不会崩溃。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "HistorySegue" {
            if let viewController = segue.destination as? HistoryController {
              if(barcodeInt != nil){
                viewController.detailItem = barcodeInt as AnyObject
               }
            }
        }
    }

【讨论】:

  • 使用 guard let 会更安全,更易读,见@Troy 回答
【解决方案2】:

一定是barcodeInt被定义为隐式解包的可选项,比如:

var barcodeInt:Int!

在这种情况下,如果在将它分配给 detailItem 时它是 nil,由于 !,swift 会相信你的话,那里有一个非 nil 值并取消引用它。这是一个运行时错误。您最好的选择是尽可能避免在您编写的代码中使用!(例如,可以保留 Apple 为 IBOutlets 生成的代码),并在返回隐式展开的选项之前了解有关选项的更多信息。然后,仍然谨慎使用它们。

更安全的代码适合您的情况:

if let viewController = segue.destination as? HistoryController, 
   let barcodeInt = barcodeInt as? AnyObject {

   viewController.detailItem = barcodeInt
} else {
   NSLog("Error: expected barcodeInt to be set") 
}

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。其逻辑是首先准备 segue(加载容器视图引用的 UIViewController),将其分配给变量,然后在 viewDidLoad() 中使用它。这段代码应该可以工作:

    斯威夫特 4.2

    // usually an IBoutlet
    var viewController: HistoryController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        viewController.detailItem = barcodeInt as AnyObject
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "HistorySegue"
        { viewController = segue.destination as! HistoryController }
    }
    

    detailItem 可以定义为 HistoryController 中的 IBoutlet,它取决于 OP 代码。在我的例子中,我有两个简单的容器视图,每个内部都有一个标签,这是主视图控制器类的最终工作代码:

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet var firstView: ReusableViewController!
        @IBOutlet var secondView: ReusableViewController!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
    
            firstView.myLabel.text = "My 1st reuse!!!"
            secondView.myLabel.text = "And that's the 2nd!"
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "segueFirstView")
            { firstView = (segue.destination as! ReusableViewController) }
            if (segue.identifier == "segueSecondView")
            { secondView = (segue.destination as! ReusableViewController) }
        }
    }
    

    这样我终于可以直接从主控制器更改两个不同 UILabel 的文本了!

    有关如何使用容器视图的详细说明,请查看this S.O. answer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-21
      相关资源
      最近更新 更多