Swift:如何通过委托从初始视图控制器向第二个视图控制器传值?
Hey there! Let's figure out why your delegate isn't passing data from the initial ViewController to RVC—you're close, but there's a key mistake in how you're connecting the two view controllers.
The Core Issue
In your RVC class, you're creating a brand new instance of ViewController with let vc = ViewController(). This is not the same ViewController instance that's actually displayed on screen! When you set vc.data = self, you're only configuring this new, unused instance—your original, visible ViewController's data property remains nil. That's why when you tap the send button, data?.sendData(data: msg) does nothing (optional chaining skips the call when data is nil).
Fixed Code & Step-by-Step Fixes
1. Update the Initial View Controller (ViewController)
First, add a prepare(for:sender:) method to handle the segue transition—this is where you'll connect the real ViewController instance to RVC:
import UIKit // Move the protocol outside the class (optional but cleaner) protocol DataDelegate: class { // Add `class` to allow weak references func sendData(data: String) } class ViewController: UIViewController { // Use weak to avoid retain cycles weak var data: DataDelegate? @IBOutlet weak var text: UITextField! @IBOutlet weak var send: UIButton! override func viewDidLoad() { super.viewDidLoad() } @IBAction func send(_ sender: Any) { // Safely unwrap the text to avoid crashes guard let msg = text.text, !msg.isEmpty else { print("Empty message, not sending") return } data?.sendData(data: msg) print("SENDING MESSAGE: \(msg)") } // This runs right before the segue to RVC override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Make sure we're navigating to RVC if let destinationVC = segue.destination as? RVC { // Set the delegate to the actual RVC instance we're about to show self.data = destinationVC } } }
2. Fix the Second View Controller (RVC)
Remove the unused ViewController instance and the line that sets its delegate—we don't need them anymore:
import UIKit class RVC: UIViewController, DataDelegate { @IBOutlet weak var delegationLabel: UILabel! @IBOutlet weak var message: UILabel! @IBOutlet weak var back: UIButton! // DELETE THIS LINE: let vc = ViewController() func sendData(data: String) { print("DATA SENT") print(data) message.text = data } override func viewDidLoad() { super.viewDidLoad() print("LOADED") // DELETE THIS LINE: vc.data = self } }
Key Additional Tips
- Weak Delegate: By making
DataDelegateinherit fromclassand declaringvar data: DataDelegate?asweak, you prevent retain cycles (memory leaks) that would happen if both view controllers held strong references to each other. - Safe Optional Handling: Using
guard letfortext.textavoids crashes if the text field is empty ornil. - Segue Setup: Make sure your storyboard has a segue from
ViewControllertoRVC(e.g., a show segue from the send button or a navigation controller), so theprepare(for:sender:)method runs when you navigate.
Now when you tap the send button in ViewController, it will call sendData(_:) on the actual RVC instance that's displayed, and your message will show up in the message label!
内容的提问来源于stack exchange,提问作者davidistan

