如何利用Protocol与Delegate实现StateListVC到PlayVC的页面跳转?
Hey there! I see the issue with your delegate setup—let's break down what's going wrong and fix it step by step.
The Core Problem
In your StateListVC's viewWillAppear method, you're creating a new instance of PlaceVC and setting its delegate, but this isn't the same PlaceVC that's inside your container view. The container view loads its child view controllers automatically from the storyboard, so your manual instance is never displayed, leaving the actual displayed PlaceVC's delegate as nil.
Step 1: Properly Assign the Delegate to the Container's PlaceVC
Instead of creating a new PlaceVC, we need to get the existing instance that's already in the container view. You can do this either by using prepare(for:sender:) (if you have a segue connected to the container) or by iterating through childViewControllers in viewDidLoad.
Option 1: Using prepare(for:sender:) (Recommended)
First, set a segue identifier for your container view's segue in the storyboard (e.g., "ContainerToPlaceVC"). Then update StateListVC:
class StateListVC: UIViewController { override func viewDidLoad() { super.viewDidLoad() } // This method catches segues to child view controllers (like your container's PlaceVC) override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "ContainerToPlaceVC" { if let placeVC = segue.destination as? PlaceVC { placeVC.delegate = self } } } } extension StateListVC: MoveToAnotherVC { func moving(string: String) { print(string) // Now navigate to PlayVC here if let playVC = storyboard?.instantiateViewController(withIdentifier: "PlayVC") as? PlayVC { // Use navigation controller push if StateListVC is in a nav stack navigationController?.pushViewController(playVC, animated: true) // Or present modally if needed: // present(playVC, animated: true) } } }
Option 2: Iterate Through Child View Controllers
If you don't want to use segues, you can find PlaceVC in viewDidLoad:
class StateListVC: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Find the PlaceVC among child view controllers let placeVC = childViewControllers.first(where: { $0 is PlaceVC }) as? PlaceVC placeVC?.delegate = self } } // Keep the MoveToAnotherVC extension the same as above
Step 2: Fix PlaceVC's TableView Selection Logic
Remove the undefined isMoveToAnotherVC variable and ensure the delegate call works correctly:
protocol MoveToAnotherVC: AnyObject { // Add AnyObject to make it a class-only protocol (safer for delegates) func moving(string: String) } class PlaceVC: UIViewController { @IBOutlet weak var tableViewPlace: UITableView! weak var delegate: MoveToAnotherVC? // Use weak to avoid retain cycles var arrPlace = ["Place1", "Place2"] override func viewDidLoad() { super.viewDidLoad() tableViewPlace.dataSource = self tableViewPlace.delegate = self } } extension PlaceVC: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return arrPlace.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = arrPlace[indexPath.row] return cell } } extension PlaceVC: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard let delegate = delegate else { print("Delegate not set") return } delegate.moving(string: arrPlace[indexPath.row]) // Pass the selected place if needed // Deselect the row for better UX tableView.deselectRow(at: indexPath, animated: true) } }
Key Improvements Added
- Weak Delegate: Marked
delegateasweakand made the protocolAnyObjectto prevent retain cycles (critical for memory management). - Correct Delegate Assignment: Targeted the actual
PlaceVCinstance in the container view, not a new one. - Navigation Logic: Added code to push/present
PlayVCin the delegate method. - UX Polish: Added
tableView.deselectRowfor better user experience.
Now when you tap a row in PlaceVC, the delegate will trigger moving(string:) in StateListVC, which will navigate to PlayVC as expected!
内容的提问来源于stack exchange,提问作者AR Tunes

