【问题标题】:Delegate/Protocols Passing data from one view controller to another委托/协议将数据从一个视图控制器传递到另一个视图控制器
【发布时间】:2018-01-23 14:17:21
【问题描述】:

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

StoryBoard and 1st VC Example Second 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)

    }
}

第二个视图控制器

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

}

【问题讨论】:

  • 崩溃信息是什么?你的代码有几个问题..
  • 就委托/协议而言...这看起来不错。 FWIW 最好将 transferNameOfCurrency 的名称更改为 CurrencyDelegate。因为它就是。它做什么 应该是其函数名称的一部分。还将func currencySelected(nameOfCurrency: String) 更改为func currencyChanged(To: String)
  • 已经修复了崩溃问题,但现在从第一个 VC 打印,显示 nameOfTheCurrency 的正确值,第二个显示 nil。

标签: ios swift delegates protocols extension-methods


【解决方案1】:

最明显的问题在这里:

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

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

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

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

编辑

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

你的第一个带有 cmets 的视图控制器:

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 推送到导航控制器的人 - 这意味着您可以直接在prepare(for:) 中访问它,如上所示。

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

import UIKit

class SecondVC: UIViewController {

    @IBOutlet weak var label: UILabel!

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

故事板可以保持原样。

【讨论】:

  • 已经尝试过 prepare(for: ) 和我现在拥有但在第二个 VC 上仍然收到 nil 的那个
  • @Ula 你试过什么?这意味着您在第二个 vc 上收到 nil 是什么意思?
  • 按下按钮时,我想将 nameOfTheCurrency 的值推送到第二个 VC,以便稍后像字符串一样使用此参数,此时当按下按钮时,我正在控制台中接收来自第一个 VC(如 EUR)的打印并从第二个 VC nil 的扩展打印。
  • 你有没有看我的回答?您并没有真正分配您想要的委托 - 您创建一个新的第一个视图控制器,它不会触发您尝试委托的那些方法..您需要对呈现的第一个视图控制器的引用..这条线没有给您参考,它创建了一个全新的视图控制器:self.storyboard?.instantiateViewController(withIdentifier: "MainScreenVC")
  • 也试过这个选项 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let viewController = segue.destination as? MainScreenVC, segue.identifier == "MainScreenVC" { viewController.transferCurrencyDelegate = self } }
猜你喜欢
  • 2020-03-20
  • 1970-01-01
  • 1970-01-01
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多