Delegate/Protocols 将数据从一个视图控制器传递到另一个
Delegate/Protocols Passing data from one view controller to another
尝试使用协议和扩展将数据从一个视图控制器 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)
}
}
第 2 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
创建了一个 new 视图控制器 - 它不是对屏幕上显示的视图控制器的引用。在该代码中,您刚刚创建了一个全新的视图控制器,然后将其委托设置为 self
,除此之外别无其他。
在不知道上下文的情况下,很难提出任何建议 - 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
推送到导航控制器的人 - 这意味着你可以直接在 prepare(for:)
中访问它,因为你可以看上面
现在 SecondVC
非常简单(我省略了不必要的代码):
import UIKit
class SecondVC: UIViewController {
@IBOutlet weak var label: UILabel!
func transferWord(word: String) {
label.text = word
}
}
故事板可以保持原样。
尝试使用协议和扩展将数据从一个视图控制器 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)
}
}
第 2 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
创建了一个 new 视图控制器 - 它不是对屏幕上显示的视图控制器的引用。在该代码中,您刚刚创建了一个全新的视图控制器,然后将其委托设置为 self
,除此之外别无其他。
在不知道上下文的情况下,很难提出任何建议 - 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
推送到导航控制器的人 - 这意味着你可以直接在 prepare(for:)
中访问它,因为你可以看上面
现在 SecondVC
非常简单(我省略了不必要的代码):
import UIKit
class SecondVC: UIViewController {
@IBOutlet weak var label: UILabel!
func transferWord(word: String) {
label.text = word
}
}
故事板可以保持原样。