如何将嵌入ViewController的TableViewController数据传回父ViewController?
Hey, I've got a couple of solid solutions for you here—since you're dealing with a parent-child controller relationship, delegation is the most idiomatic approach in iOS, and it'll work perfectly for your case. Let's walk through it step by step, plus I'll throw in a simpler closure alternative if you prefer.
First, let's fix why your earlier attempt failed: when you instantiated a new PayViewController inside UsersTableViewController, you were creating a completely separate instance—this wasn't the same controller that's actually displaying your input fields, so setting text there had no effect on the screen. We need to communicate with the existing parent controller instead.
Solution 1: Delegation (iOS Standard Practice)
This is the cleanest, most scalable way for child-to-parent communication.
Step 1: Define a Delegate Protocol in UsersTableViewController
Add this above your UsersTableViewController class:
protocol UsersTableViewControllerDelegate: AnyObject { func didSelectUser(withEmail email: String) }
Then add a weak delegate property inside the class:
class UsersTableViewController: UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating { // Add this line weak var delegate: UsersTableViewControllerDelegate? // ... rest of your existing code }
Step 2: Trigger the Delegate When a Cell is Selected
Update your didSelectRowAt method to call the delegate with the selected email:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedUser: NSDictionary if searchT != "" { selectedUser = filteredUsers[indexPath.row]! } else { selectedUser = usersArray[indexPath.row]! } if let userEmail = selectedUser["email"] as? String { // Pass the email to the parent via delegate delegate?.didSelectUser(withEmail: userEmail) // Optional: Deselect the row for better UX tableView.deselectRow(at: indexPath, animated: true) } }
Step 3: Implement the Delegate in PayViewController
First, update your class declaration to conform to the new protocol:
class PayViewController: UIViewController, STPAddCardViewControllerDelegate, UsersTableViewControllerDelegate { // ... rest of your existing code }
Then set the delegate in viewDidLoad, and add the delegate method to handle the incoming email:
override func viewDidLoad() { super.viewDidLoad() amountLabel.text = "$ \(finalAmount)" myTable = self.children[0] as! UsersTableViewController // Set the delegate here myTable?.delegate = self self.toField.addTarget(myTable, action: #selector(UsersTableViewController.textChanges(_:)), for: .editingChanged) } // Implement the delegate method func didSelectUser(withEmail email: String) { // Update your input field with the selected email forField.text = email // Optional: Dismiss the keyboard forField.resignFirstResponder() }
Solution 2: Closure (Simpler for One-Time Communication)
If you don't need a full delegate pattern for multiple interactions, a closure is a more concise option.
Step 1: Add a Closure Property to UsersTableViewController
class UsersTableViewController: UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating { // Add this closure property var onUserSelected: ((String) -> Void)? // ... rest of your existing code }
Step 2: Call the Closure When a Cell is Selected
Update didSelectRowAt:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedUser: NSDictionary if searchT != "" { selectedUser = filteredUsers[indexPath.row]! } else { selectedUser = usersArray[indexPath.row]! } if let userEmail = selectedUser["email"] as? String { // Trigger the closure with the email onUserSelected?(userEmail) tableView.deselectRow(at: indexPath, animated: true) } }
Step 3: Assign the Closure in PayViewController
Set this up in viewDidLoad:
override func viewDidLoad() { super.viewDidLoad() amountLabel.text = "$ \(finalAmount)" myTable = self.children[0] as! UsersTableViewController // Assign the closure to handle the selected email myTable?.onUserSelected = { [weak self] email in self?.forField.text = email self?.forField.resignFirstResponder() } self.toField.addTarget(myTable, action: #selector(UsersTableViewController.textChanges(_:)), for: .editingChanged) }
Both approaches will work perfectly—delegation is better if you ever need to add more communication between the controllers later, while closures are quicker for simple one-way data passes.
内容的提问来源于stack exchange,提问作者Jose Luis Montalvo Ferreiro

