控制器之间经常需要互相传递值,第一个控制器(简称 MasterVC)在通过 NavigationController Push 第二个控制器(简称 DetailVC)的时候,可以捕获到 DetailVC,所以可以设定后者的变量。而 DetailVC 在给 MasterVC 传递值的时候,比如设定 MasterVC 的 Title,却不能用同样的方式传值(试一下就知道了),而且因为我们要通过 NavigationController 返回原来的界面而不是 push 一个新的界面,所以也不能通过 segue 传值,解决方法我尝试了两种:
- 使用 static var
- 使用代理传值
使用 static var
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 内部,仍然需要以 <code>MasterVC.text</code> 这样蹩脚的方式调用。
使用代理传值
说白了我们只是希望 MasterVC 有一个 <code>setControllerTitle(text:String)</code> 这样的方法,然后在 DetailVC 里面适时地调用这个方法就好了。于是解决方案是:将 MasterVC 设为 DetailVC 的代理,DetailVC 以代理作为桥梁,来调用 MasterVC 里面的 <code>setControllerTitle(text:String)</code> 方法,而 MasterVC 只需要遵守一个相应的传值协议,协议里面要求必须实现的方法,就是 <code>setControllerTitle(text:String)</code> 这个方法。
// 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)
}
}
相比之前的方法,我们获得的额外的好处是:假如我们传递的不只是字符串,而是大量的信息,比如十个不同类型的值,使用代理传值依然只需要实现一个方法,而在之前的解决方案中,我们需要写十行 <code>static var</code>。