如何从嵌入在ViewController中的tableViewController向该视图控制器发送信息?

时间:2019-02-09 01:01:06

标签: ios swift uitableview uiviewcontroller

我有一个视图控制器,在该视图控制器内,我有一个表视图控制器(see image here)

程序的工作方式如下:

用户正在输入某人的电子邮件地址,表视图正在随着用户输入而更新。

一旦用户确信该表正在显示所需的单元格,就可以单击它,并且按下的单元格中的信息会“自动完成”用户键入的内容。

我同时拥有两个视图控制器(一个表视图和一个常规视图控制器)。我知道如何将信息从viewController发送到tableViewController,但是我不知道如何反向发送信息。随附的是viewController的代码:

class PayViewController: UIViewController, STPAddCardViewControllerDelegate {


    var finalAmmount = ""
    var toPay = 0.00
    var successfullPayment = false
    var payToUser = ""
    var updatedBalance = ""

    lazy var functions = Functions.functions()
    var resultText = "" // empty
    var input = ""
    var email = ""

    var sele = ""

    @IBOutlet weak var forField: UITextField!
    @IBOutlet weak var toField: UITextField!
    @IBOutlet weak var ammountLabel: UILabel!

    //toField.addTarget(self, action: #selector(UsersTableViewController.textChanges(_:)), for: UIControl.Event.editingChanged)
    var myTable:UsersTableViewController?

    override func viewDidLoad() {
        super.viewDidLoad()
        //var myTable:UsersTableViewController?
        ammountLabel.text = "$ \(finalAmmount)"
        myTable = self.children[0] as! UsersTableViewController
        self.toField.addTarget(myTable, action: #selector(UsersTableViewController.textChanges(_:)), for: UIControl.Event.editingChanged)
    }


    @IBAction func paraFieldEdditingStarted(_ sender: Any) {
         myTable!.filterContent(searchText:forField.text!)
        //self.toField.addTarget(, action: #selector(UsersTableViewController.textChanges(_:)), for: UIControl.Event.editingChanged)
    }

,以下是tableViewController的代码

class UsersTableViewController: UITableViewController, UISearchResultsUpdating {

    func updateSearchResults(for searchController: UISearchController) {
        //update the search results
        filterContent(searchText: searchT)
    }


    @objc func textChanges(_ textField: UITextField) {
        let text = textField.text! // your desired text here
        // Now do whatever you want.
        searchT = text
        filterContent(searchText:textField.text!)
    }


    @IBOutlet var usersTableView: UITableView!
    let searchController = UISearchController(searchResultsController: nil)

    var searchT = ""
    var usersArray = [NSDictionary?]()
    var filteredUsers = [NSDictionary?]()

    var databaseRef: DatabaseReference!


    override func viewDidLoad() {
        super.viewDidLoad()

        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true

        tableView.tableHeaderView = searchController.searchBar

        databaseRef = Database.database().reference()
        let usersRef = databaseRef.child("users")
        let query = usersRef.queryOrdered(byChild: "email")
        query.observe(.childAdded, with: {(snapshot) in
            self.usersArray.append((snapshot.value as? NSDictionary?)!)

            //insert the rows
            self.usersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1, section: 0)], with: UITableView.RowAnimation.automatic)


        }) { (error) in
            print(error.localizedDescription)
        }

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows

        if (self.searchT != ""){
            return filteredUsers.count
        }
        return self.usersArray.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let user: NSDictionary
        if ((searchT != "")){
            user = filteredUsers[indexPath.row]!
        }else{
            user = self.usersArray[indexPath.row]!
        }

        cell.textLabel?.text = user["email"] as? String
        cell.detailTextLabel?.text = user["name"] as? String

        return cell
    }

    func filterContent(searchText: String){

        self.filteredUsers =  self.usersArray.filter({ user in
            let userEmail = user!["email"] as? String
            return(userEmail?.lowercased().contains(searchText.lowercased()))!
        })

        tableView.reloadData()
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //let vc = storyboard?.instantiateViewController(withIdentifier: "ConfirmationVC") as? PayViewController
        //vc?.forField.text = filteredUsers[indexPath.row]!["email"] as! String
    }

    func setContents(searchText: String){
       // searchT = searchText
    }
正如您在tableviewcontroller的最后看到的那样,

我尝试使用vc发送信息。有没有更简单的方法?

2 个答案:

答案 0 :(得分:0)

您的尝试

let vc = storyboard?.instantiateViewController(withIdentifier: "ConfirmationVC") as? PayViewController

...失败,因为它创建了PayViewController的新的,不同的实例-而不是包含此UsersTableViewController的实例。

PayViewController是此UsersTableViewController的parent。您可能需要将其强制转换为PayViewController才能调用方法或在其中设置属性:

let vc = self.parent as? PayViewController

(请注意,在您尝试执行操作时,一个视图控制器直接设置另一个视图控制器的接口是不寻常的。您应该为PayViewController提供一种可以让UsersTableViewController良好调用的方法。)

答案 1 :(得分:0)

尽管创建委托协议并将委托属性添加到tableViewController是一种不错的方法,但还有另一种方法。

只需在您的tableViewController中添加一个闭包属性即可:

var updatedData: ((_ email: String, _ name: String)->Void)?

您的tableViewController可以通过简单地调用

将信息“发送到上游”到未知的父视图控制器。
self.updatedData?(theEmail, theName)

在您的父视图控制器的viewDidLoad(或您选择的任何位置)中,执行以下操作:

tableViewController.updatedData = 
  { [weak self] email, name in
      // do your code here
  }

非常简单。与正式协议相比,此方法有多种利弊。我强烈建议您尝试使用这两种方法,并且对这两种方法都非常熟悉,以便随着时间的流逝,您将了解何时使用哪种方法。这种方法是非正式的,通常更适合在应用程序内(相对于SDK)进行“上链”通信,尤其是在父视图控制器不太可能换成另一个的情况下。但是说您总是想通过协议对所有内容进行形式化也完全合理。那样只是多了一点代码。

我实际上经常使用这种非正式方法。我还将这些闭包变量打包到我的视图模型将要实现的协议中,只是为了在我独立于我的应用程序进行UI测试单个视图控制器时可以依赖注入另一个视图模型。无论如何,这是不同的情况(viewModel与viewController进行通信,而不是您的子viewController与父viewController进行通信)。