我想在两个ViewControllers之间传递数据抛出TabBarController。 在第一个ViewController里面我找到了textField和button。 在第二个我找到标签。 当我在textField和push按钮中写一些文本时,我希望这个文本出现在第二个ViewController的Label中。但没有任何反应。
我的代码:
First ViewController:
import UIKit
class FirstViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBAction func enter(_ sender: Any) {
if textField.text != "" {
if let window = UIApplication.shared.delegate?.window, let tabBarController = window?.rootViewController as? UITabBarController, let second = tabBarController.viewControllers?.first as? SecondViewController {
second.label.text = textField.text
tabBarController.selectedIndex = 0
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
第二个ViewController:
import UIKit
class SecondViewController: UIViewController {
@IBOutlet weak var label: UILabel!
var myString = String()
override func viewDidLoad() {
super.viewDidLoad()
label.text = myString
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
答案 0 :(得分:0)
我认为问题在于
tabBarController.viewControllers?.first as? SecondViewController
你可能想要这样做:
tabBarController.viewControllers?[1] as? SecondViewController
不要忘记数组从0开始索引,因此viewControllers?[1]
实际上返回数组中的第二个元素。
答案 1 :(得分:0)
首先,我认为代表制表符的视图控制器应嵌入到导航控制器中,然后导航控制器将链接到TabBarController。
其次,在控制器之间发送数据的优先和推荐方法是通过协议(委托)。这是一个很好的例子,您可以一步一步地查看:https://medium.com/@jamesrochabrun/implementing-delegates-in-swift-step-by-step-d3211cbac3ef
但是,如果您正在寻找解决方案的快速解决方案,我认为Bruno Phillipe的答案在某种程度上得到了它,但并不完全。我们无法确定控制器在视图控制器列表中的哪个索引处。我认为这应该有效:
@IBAction func enter(_ sender: Any) {
if textField.text != "" {
if let window = UIApplication.shared.delegate?.window, let tabBarController = window?.rootViewController as? UITabBarController {
//check if there are view controllers in the tabBarController
guard let vcList = tabBarController.viewControllers else {
return
}
for controller in vcList {
if let second = controller as? SecondViewController {
//this will be executed only when a controller is SeconfViewController
second.label.text = textField.text
tabBarController.selectedIndex = 0
}
}
}
}
}
编辑:
我自己尝试了,问题是你试图设置label.text,实际上标签组件从未初始化。我想如果你只是将textField值存储到SecondViewController中的myString变量中,它就可以工作(不确定)。
然而,这是使用协议(委托)的解决方案,这是在控制器之间发送数据的正确方法。问你可能有任何问题。这应该有效:
FirstViewController:
import Foundation
import UIKit
protocol LabelChangeDelegate: class {
func changeLabelWithText(_ text: String?)
}
class FirstViewController: UIViewController {
weak var delegate: LabelChangeDelegate?
@IBOutlet weak var textField: UITextField!
@IBAction func enter(_ sender: UIButton) {
if textField.text != "" {
if let window = UIApplication.shared.delegate?.window, let tabBarController = window?.rootViewController as? UITabBarController {
//check if there are view controllers in the tabBarController
guard let vcList = tabBarController.viewControllers else {
return
}
for controller in vcList {
if let second = controller as? SecondViewController {
//this will be executed only when a controller is SeconfViewController
//set the delegate - who needs the data
delegate = second
//call the delegate function which will commmunicate with the delegate
delegate?.changeLabelWithText(textField.text!)
//don't know why you need this
tabBarController.selectedIndex = 0
}
}
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
SecondViewController:
import Foundation
import UIKit
class SecondViewController: UIViewController, LabelChangeDelegate {
@IBOutlet weak var label: UILabel!
//lazy init
lazy var myString = String()
override func viewDidLoad() {
super.viewDidLoad()
//set label when the view loads, not in the first controller
label.text = myString
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//delegate function
func changeLabelWithText(_ text: String?) {
guard let sentText = text else {
//no text sent
return
}
myString = sentText
}
}
答案 2 :(得分:0)
我不建议你这样做。这是对理解的解释。
tabBarController
。您可以使用self.tabBarController
。secondViewController
是viewControllers
列表中的第二个let second = tabBarController.viewControllers?[1] as? SecondViewController
。secondViewController
,则其视图将无法加载,因此网点仍为nil
。您可以使用_ = second.view
。tabBarController.selectedIndex = 1
。@IBAction func enter(_ sender: Any) {
if textField.text != "" {
if let tabBarController = self.tabBarController as? UITabBarController, let second = tabBarController.viewControllers?[1] as? SecondViewController {
// make sure view has loaded
_ = second.view
second.label.text = textField.text
// change to second tab
tabBarController.selectedIndex = 1
}
}
}
更好的方法......
您应该将字符串传递给SecondViewController
的属性,而不是直接设置插座:
second.myString = textField.text ?? ""
然后在label
的覆盖中将该字符串分配给viewWillAppear
。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
label.text = myString
}
在viewWillAppear
中设置它的原因是viewWillAppear
每次都会在显示视图之前运行。 viewDidLoad
只会在首次加载视图时运行一次。由于您希望功能多次工作,viewWillAppear
是正确的覆盖。