1.はじめに
初投稿です。備忘録として書いているので、わかりにくいかもしれません。
デリゲートとプロトコルを使用して、ViewControllerB→Aに値を渡し処理するコードは以前から使っていましたが、その逆のViewControllerA→Bに渡せないかと思い試してみました。
2.試したこと
1.ViewControllerAからBにデリゲートを使用して値を送る。(PassData Forward)
2.ViewControllerBからAにデリゲートを使用して値を送る。(PassData BackWard)
詳細はコードの中にコメントを残したので番号順に追ってみてください。
3.所感
もしかしたら、使い所があるのかもしれませんが、デリゲートとプロトコルを使用してViewControllerA→Bに値を渡すのは面倒なので、シンプルにprepare(for segue)等で値を渡した方が楽に感じました。
4.コード(ViewControllerA)*動作確認済
import UIKit
//⑤(PassData Forward)プロトコルとデリゲートを使用し、ViewControllerからデータを取得し、SecondViewControllerで処理する。
protocol DataProvider: class {
func provideData() -> String?
}
//②(PassData Forward) プロトコルDataProviderの通知先を通知先をSelfに指定。
protocol DataHandler: class {
//prepforsegue時にproviderDelegate = selfがセットされる。
var delegateForward: DataProvider? { get set }
}
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
var name: String = ""
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
@IBAction func button(_ sender: Any) {
performSegue(withIdentifier: "goNext", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//*ココでViewController内のプロトコルDataProviderの処理を実施すると、まだSecondViewが生成されていないため、nilとなる。
//①(PassData Forward) よって、Delegateの通知先をプロトコルDataHandlerを通じてSecondViewControllerに伝える。
if let destination = segue.destination as? DataHandler {
destination.delegateForward = self
}
//①(PassData BackWard)Delegateの通知先をSecondViewに伝える。
if let destination = segue.destination as? SecondViewController{
destination.delegateBackward = self
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
//⑥(PassData Forward)
//プロトコルとデリゲートを使用し、SecondViewControllerでDelegateが呼ばれた際に以下の処理をし、SecondViewに値を渡す。
extension ViewController: DataProvider {
func provideData() -> String? {
return textField.text
}
}
//④(PassData BackWard)
//プロトコルとデリゲートを使用し、SecondViewControllerからデータを取得し、ViewControllerで処理する。
extension ViewController: provideDataBackward{
func passData(text: String?) {
textField.text = text
}
}
4.コード(ViewControllerB)*動作確認済
import UIKit
protocol provideDataBackward {
func passData(text:String?)
}
class SecondViewController: UIViewController, UITextFieldDelegate, DataHandler{
//③(PassData Forward)プロトコルDataHandlerを通じてViewControllerで設定されたプロトコルDataProviderのDelegate通知先を記憶している。
weak var delegateForward: DataProvider?
//③Segue時にViewControllerで設定されたDelegateの通知先(ViewController = self)を記憶している。
var delegateBackward:provideDataBackward?
@IBOutlet weak var textField: UITextField!{
didSet{
//④(PassData Forward) ViewControllerのプロトコルDataProviderのメソッドprovideData()から値を取り出す。
//⑦(PassData Forward) 取り出した値をテキストフィールドに表示⑦
if let data = delegateForward?.provideData(){
textField.text = data
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
// Do any additional setup after loading the view.
}
@IBAction func button(_ sender: Any) {
navigationController?.popToRootViewController(animated: true)
// ②(PassData Backward) ViewController内でdelegateBackwardに設定された通知先(ViewController = self)にdelegateが実施されたことを伝え、データを渡す。
delegateBackward?.passData(text: textField.text)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
4.引用
Stack Overflow
Why passing data with delegate fails in Swift 4