控制器之间经常需要互相传递值,第一个控制器(简称 MasterVC)在通过 NavigationController Push 第二个控制器(简称 DetailVC)的时候,可以捕获到 DetailVC,所以可以设定后者的变量。而 DetailVC 在给 MasterVC 传递值的时候,比如设定 MasterVC 的 Title,却不能用同样的方式传值(试一下就知道了),而且因为我们要通过 NavigationController 返回原来的界面而不是 push 一个新的界面,所以也不能通过 segue 传值,解决方法我尝试了两种:
class MasterVC: UIViewController { static var text:String! = "" override func viewWillAppear(animated: Bool) { title = MasterVC.text } } class DetailVC: UIViewController { override func viewWillDisappear(animated: Bool) { MasterVC.text = "xxx" } }
这样虽然行得通,但是代码丑陋:类似 viewWillAppear 这样的方法,让人难以读懂,为什么这样的事情要在这个地方做,没有明显的道理;在 MasterVC 内部,仍然需要以 MasterVC.text
这样蹩脚的方式调用。
说白了我们只是希望 MasterVC 有一个 setControllerTitle(text:String)
这样的方法,然后在 DetailVC 里面适时地调用这个方法就好了。于是解决方案是:将 MasterVC 设为 DetailVC 的代理,DetailVC 以代理作为桥梁,来调用 MasterVC 里面的 setControllerTitle(text:String)
方法,而 MasterVC 只需要遵守一个相应的传值协议,协议里面要求必须实现的方法,就是 setControllerTitle(text:String)
这个方法。
// PassDataDelegate.swift import Foundation protocol PassDataDelegate { func setControllerTitle(text:String) } // MasterVC.swift import UIKit class MasterVC: UIViewController, PassDataDelegate { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() } // MARK: - Pass Data @IBAction func goNextController(sender: AnyObject) { guard let vc = storyboard?.instantiateViewControllerWithIdentifier("DetailVC") as? DetailVC else { return } guard let txt = textField.text else { return } vc.title = txt // pass data vc.delegate = self // get data by set delegate navigationController?.pushViewController(vc, animated: true) } // MARK: - PassDataDelegate Method func setControllerTitle(text:String) { title = text } } // DetailVC.swift import UIKit class DetailVC: UIViewController { @IBOutlet weak var textField: UITextField! var delegate: PassDataDelegate! override func viewDidLoad() { super.viewDidLoad() } // MARK: - Pass Data @IBAction func goBackLastController(sender: AnyObject) { if delegate != nil { guard let txt = textField.text else { return } delegate.setControllerTitle(txt) } navigationController?.popViewControllerAnimated(true) } }
相比之前的方法,我们获得的额外的好处是:假如我们传递的不只是字符串,而是大量的信息,比如十个不同类型的值,使用代理传值依然只需要实现一个方法,而在之前的解决方案中,我们需要写十行 static var
。
完整项目