问题描述
我有两个 viewController:第一个有一个 tableView,第二个有一个带有动作的 textField,如果在 textFiled 中插入了特定的文本,我想调用 loadData1()
函数,它有orderTable.reloadData()
从 logInviewController
重新加载 tableView,但是当我调用它时它返回 nil。
tableViewController 代码:
import UIKit
import FirebaseFirestore
import Firebase
import FirebaseAuth
class orderTableViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UITextFieldDelegate {
@IBOutlet var orderTable: UITableView!
var db: Firestore!
var firstName = [String]()
var lastName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
orderTable.register(UINib(nibName: "Order1TableViewCell",bundle: nil),forCellReuseIdentifier: "orderCell")
}
func loadData1() {
Firestore.firestore().collection("hola").getDocuments() { [self]
(querySnapshot,err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
for document in querySnapshot!.documents {
self.firstName.append(document.get("firstname") as? String ?? "")
self.lastName.append(document.get("lastname") as? String ?? "")
}
}
orderTable.reloadData() // from here i got Unexpectedly found nil while unwrapping an Optional value:
}
}
}
}
logInViewController 代码:
import UIKit
import Firebase
import FirebaseAuth
class logInViewController: UIViewController,UITextFieldDelegate {
@IBOutlet var userNameField: UITextField!
@IBOutlet var passwordField: UITextField!
@IBOutlet var logInButton: UIButton!
var db: Firestore!
var order: orderTableViewController!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func textfieldDidChange(_ sender: Any) {
print(userNameField?.text ?? "")
if userNameField.text == "v@v.com" {
let i = orderTableViewController()
i.loadData1()
}
}
}
解决方法
如果你有 let i = orderTableViewController()
,你不是在引用你现有的表视图控制器,而是创建一个新的,除了这次它没有与故事板场景一起实例化,因此你所有的 { {1}} 引用将为零。尝试引用这些 @IBOutlet
引用将失败。
要解决此问题,您应该使用协议而不是显式类名将第一个视图控制器的引用传递给第二个视图控制器,然后第二个视图控制器可以调用第一个视图控制器中的方法。因此:
-
创建类协议,例如
@IBOutlet
:LoginViewControllerDelegate
-
给该协议一个方法要求,
protocol LoginViewControllerDelegate: class { }
:loadData1
-
使您的第一个视图控制器符合该协议:
protocol LoginViewControllerDelegate: class { func loadData1() }
-
在第二个视图控制器中创建一个属性
extension OrderTableViewController: LoginViewControllerDelegate { func loadData1() { ... your implementation here ... } }
,用于此委托协议引用,例如:LoginViewController
-
当第一个视图控制器实例化第二个时,设置此
weak var delegate: LoginViewControllerDelegate?
属性(例如,如果执行转场,它将在delegate
中):prepareForSegue
-
然后第二个视图控制器将调用
override func prepare(for segue: UIStoryboardSegue,sender: Any?) { if let destination = segue.destination as? LoginViewController { destination.delegate = self } }
而不是delegate?.loadData1()
。
如果你按照我的理解去做,那么你就可以做到。但是你应该使用委托或闭包回调来做到这一点。
@IBAction func textfieldDidChange(_ sender: Any) {
print(userNameField?.text ?? "")
if userNameField.text == "v@v.com" {
if let i = order {
i.loadData1()
}
}
}
}