如何在 ViewController 之间传输数据?

How to transfer data between ViewControllers?

我目前正在开发货币汇率应用程序。我有一个 main ViewController,它有一个 UILabel,它显示 selected 货币的解析汇率。此外,还有一个按钮用于更改其中一种货币汇率以获得新汇率(second ViewController 显示为 N tableView 单元格).
我在将新 selected 值的数据传输到 main ViewController 时遇到了一些麻烦。当我 select 一个新的汇率时,我得到了 UILabel 的这个错误:

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

我想我知道如何修复它 - 在 main 中创建一个变量并在 second viewcontroller 中设置它的值,但我不知道如何正确地做。这是我的代码。提前致谢。

class MainVC: UITableViewController {

    var convertedValue: String = ""

    // some stuff

    func parseCurrency(top: String) {
        let URL_Exchange = URL(string: "MY URL\(top)")!
        let task = URLSession.shared.dataTask(with: URL_Exchange) {(data, response, error) in
            guard let data = data else { return }
            let queue = DispatchQueue(label: "result")
            queue.async {
                let JSON = String(data: data, encoding: .utf8)
                let jsonData = JSON!.data(using: .utf8)!
                let result: Rates = try! JSONDecoder().decode(Rates.self, from: jsonData)
            
                let currencies = result.conversion_rates?.dictionary
                var doubleVar:Double = 0
                for item in currencies! {
                    if (item.key == self.BottomCurrency.sublabel) {
                        doubleVar = item.value as! Double
                    }
                }
            
                // this value is the text to print inside "Result" Label
                let mult = Double(round(10000*doubleVar * self.InputText)/10000)
             

                self.convertedValue = String(mult)
                DispatchQueue.main.async {
                    if self.convertedValue == "0" {
                        self.Result.text = String(0)
                    } else {
                        // Here I get an error
                        self.Result.text = self.formatNumber(num: Double(self.convertedValue))
                    }
                }
            }
    
        }
        task.resume()
}

second的代码VC:

class SecondVC: UITableViewController {
    private var temp: Int = 0

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        if isBeingDismissed {
            // updating temp value...
            let vc = storyboard!.instantiateViewController(withIdentifier: "main") as! MainVC
            vc.parseCurrency(top: Currencies[temp].short)
            // or to call vc.convertedValue = something
            // vc.parseCurrency(...)
        }
    }

如果我不得不猜测,您的代码崩溃的原因是您在新创建的 main 视图控制器实例上调用的 属性 Result 实际上是IBOutlet 指向尚未创建的 UILabel!

重要!

Internet 上有大量关于在视图控制器之间传递数据的资源,因此我将您指向已经存在的 post,并提供了大量答案:Passing data between view controllers

但是,我将在下面描述一种可用的解决方法

委派

解决它的一种方法是使用“传统的”UIKit 模式,即 Delegation

您只需创建一个协议,即可实现 secondVCmainVC

通信的方式
protocol SecondVCDelegate: AnyObject {
    func secondVCDidSelect(currency: String)
}

然后你在secondVC

上加一个weak属性
class SecondVC: UITableViewController {

    weak var delegate: SecondVCDelegate?

    // ...

}

现在您应该可以将您想要的任何值传递给委托。为了这个例子,你可以在 temp 属性

didSet 观察者上做
class SecondVC: UITableViewController {

    private var temp: Int = 0 {
        didSet {
            delegate?.secondVCDidSelect(currency: Currencies[temp].short)
        }
    }

    weak var delegate: SecondVCDelegate?

}

Personally I would call the delegate the moment user is selecting the value, and not store it in the temp property

唯一缺少的是将 mainVC 设置为 secondVC 的委托并遵守协议。完美的地方是在你展示来自 mainVC

secondVC 的那一刻
let viewController: SecondVC = // init SecondVC or load from storyboard
viewController.delegate = self
// present secondVC
extension MainVC: SecondVCDelegate {
    func secondVCDidSelect(currency: String) {
        parseCurrency(top: currency)
    }
}

我鼓励您阅读更多关于委托的内容,因为这是 iOS 开发中非常流行的模式

Delegation in Swift 约翰·桑德尔