Swift 3 - 准备Segue

5

在我的故事板中有三个场景。我的初始视图控制器是一个导航控制器,然后有一个关系根视图控制器到一个UI视图控制器(视图控制器a),然后我有一个从ViewController中的按钮到第三个ViewController(视图控制器b)的推动连续剧。我已经给了推送连续剧一个标识符。现在我正在尝试准备我的连续剧,在第二个视图控制器(view controller a)中这样做:

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的隐式解包可选项

我做错了什么?


1
barcodeInt是什么?请提供更多细节。 - Lumialxk
detailItembarcodeInt 的类型是什么? - Danh Huynh
3个回答

10

请用以下代码替换您的代码,这样至少不会崩溃。

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 的回答。 - Pseudonym Patel

1

必须将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") 
}

0
我曾经遇到过同样的问题。解决方法是首先准备好segue(加载由容器视图引用的UIViewController),将其分配给一个变量,然后在viewDidLoad()中使用它。以下代码应该可以解决问题: Swift 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的文本了!

关于如何使用容器视图的详细说明,可以查看这个S.O.答案


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接