Swift Delegate カスタムセル 実装処理

delegateについて記事を探したが、一般論でしかなく理解し難いのでまとめておく

やりたいこと

TableView Cellの中のbutton で画面遷移したい。delegate利用

理由:通常ならデリゲートメソッドを利用する。
しかし、xibファイルの中に自分が実装したボタンがあり、ボタン押下時に画面遷移したい。
そのときに選択したセルのオブジェクトも持っていきたい。

通常ならセル選択時に呼ばれるメソッドを利用。これ

 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){

しかし,xibファイルはこれ

f:id:happy_teeth_ago:20190530082902p:plain

xibファイルのボタン押下を取得するために,delegateを自作。

まずプロトコル 今回は、セルのindexPath を次画面で利用したいため、引数に渡してあげる。

protocol UseSegueDelegate {

//この関数は、delegateを任された側のクラスで、実装しないといけない。
    func moveView(_ index: IndexPath)

}

ちなみに、プロトコル名は○○delegateのほうがわかりやすい。

処理を任せる側 xibファイルのクラス

//DayListCellクラス
//引数用のプロパティ
   var index:IndexPath?
//これが無いと、delegateメソッドが利用できない。
    var delegate:UseSegueDelegate?
    
    @IBOutlet weak var count: UILabel!
    
    @IBOutlet weak var dayLabel: UILabel!
    @IBAction func btn_NextPage(_ sender: Any) {
            delegate?.moveView(index!)
    }

実装するクラス tableviewのあるクラス

  //delegate
    var index:IndexPath?
    
    // PlanListControllerからの画面遷移時にデータを持ってくる
    var plan: Plans?
    //日付表示用
    var planDays: [Days]?


 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // セルを取得する 先程のxib ファイルにキャストする
        let cell: DayListCell = tableView.dequeueReusableCell(withIdentifier: "DayCell", for: indexPath) as! DayListCell

//日付表示用        
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "ja_JP")
        formatter.dateStyle = .medium

        // セルに表示する値を設定する
        let date = planDays![indexPath.row].day
        cell.count.text = "\(String(planDays![indexPath.row].day + 1)) 日目"
        let dateComponents = DateComponents(day: Int(date))

        //datecomponents でday を指定しているのでその分増えていく 1-足す時間 2-開始時間
        let showDay = Calendar.current.date(byAdding: dateComponents, to: plan!.start_date!)
        cell.dayLabel.text = formatter.string(from: showDay!)

        //xibファイルのdelegateには、このコントロラーを渡す
        cell.delegate = self
//ポイント ここでdelegateのプロパティにTableViewのindexPathを詰め込んでいる
        cell.index = indexPath
        return cell
    }

上記のポイントの箇所により - プロトコルのプロパティ indexにこのTableViewのindexPathが詰め込まれる - プロトコルのメソッド func moveView(_ index: IndexPath)が呼ばれる これはセルのなかのボタン押下時に呼ばれる。indexpathが詰め込まれている
- その後同じクラスに実装しているmoveViewが呼ばれる

  func moveView(_ index: IndexPath) {
        //self.index= このクラスのプロパティ
        self.index = index
//segueを呼ぶ
        performSegue(withIdentifier: "toFoodList", sender: nil)
    }


//上記performSegueにより呼び出される
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "toFoodList") {
            let subView = (segue.destination as? FoodListControllerTableViewController)!
            // modify
            subView.day_int = self.plan?.days
//ここでindexが利用できる。 このプロトコルを実装していないと、[index!.row]を記載するとエラーになる。
//プロトコルを実装したために、エラーにならない。
            subView.day = self.planDays![index!.row]
        }
    }