繁体   English   中英

委托/协议将数据从一个视图控制器传递到另一个

[英]Delegate/Protocols Passing data from one view controller to another

试图通过协议和扩展名将数据从一个视图控制器MainScreenVC传递到另一个RatesVC,但这无法正常工作,每次应用程序崩溃。 我清楚地看到第二个VC上的代码有问题(因为在第一个VC上执行操作后打印显示正确的数据),但是不确定哪里出了错误。

StoryBoard和第一个VC示例 第二个VC

第一视图控制器

import UIKit

protocol transferNameOfCurrency {
    func currencySelected(nameOfCurrency: String)
}

class MainScreenVC: UIViewController {

    var transferCurrencyDelegate: transferNameOfCurrency?
    var nameOfTheCurrency: String?

    @IBAction func updateRates(_ sender: Any) {
        nameOfTheCurrency = "EUR"
        transferCurrencyDelegate?.currencySelected(nameOfCurrency: 
nameOfTheCurrency)
        print(nameOfTheCurrency)

    }
}

第二个ViewController

import UIKit

class RatesVC: UIViewController {
    var currencySelected: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let push = self.storyboard?.instantiateViewController(withIdentifier: "MainScreenVC") as? MainScreenVC
        {
            push.transferCurrencyDelegate = self
        }

         // Do any additional setup after loading the view.
    }
}

extension RatesVC: transferNameOfCurrency {
    func currencySelected(nameOfCurrency: String) {
       currencySelected = nameOfCurrency
       print(currencySelected)
    }

}

最明显的问题在这里:

if let push = self.storyboard?.instantiateViewController(withIdentifier: "MainScreenVC") as? MainScreenVC {
    push.transferCurrencyDelegate = self
}

您必须意识到instantiateViewController会创建一个新的视图控制器-它不是对屏幕上显示的视图控制器的引用。 在该代码中,您刚刚创建了一个全新的视图控制器,然后将其委托设置为self ,但除此之外别无其他。

在不知道上下文的情况下,很难提出任何建议-prepare prepare(for:) segue可能是您要设置委托的地方。 无论如何,问题在于您必须获得对屏幕上显示的控制器的引用,该控制器应该对这些事件做出反应。

此外,从内存管理方面,您应该真正考虑将delegate属性设置为weak属性,以防止内存泄漏。

编辑

因此,在看到您在link上提供的最小工作示例之后,我想我可以提供有关如何将字符串获取到SecondVC的解决方案。

您的第一个带有评论的视图控制器:

import UIKit

class ViewController: UIViewController {

    var newLine: String = "EUR"

    @IBAction func push(_ sender: Any) {
        // here the secondVC does not exist yet, calling delegate.transferWord() here would have no sense
        // performSegue will create that secondVC, but now it does not exist, nor it is set up as the delegate
        self.performSegue(withIdentifier: "ViewController", sender: navigationController)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let secondVC = segue.destination as? SecondVC, segue.identifier == "ViewController" {
            // at this moment secondVC did not load its view yet, trying to access it would cause crash
            // because transferWord tries to set label.text directly, we need to make sure that label
            // is already set (for experiment you can try comment out next line)
            secondVC.loadViewIfNeeded()
            // but here secondVC exist, so lets call transferWord on it
            secondVC.transferWord(word: newLine)
        }
    }
}

这里不需要委托,因为ViewController是将SecondVC推向Navigation控制器的代表-这意味着您可以直接在prepare(for:)访问它,如您在上面看到的。

现在SecondVC非常简单(我省略了不必要的代码):

import UIKit

class SecondVC: UIViewController {

    @IBOutlet weak var label: UILabel!

    func transferWord(word: String) {
        label.text = word
    }
}

故事板可以保持原样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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