Swift - 愛不釋手的 Closure

「在 A View 叫起B View做動作,成功或失敗各自有不同的行為,但這個行為得依賴A頁拿到得資料有所不同時應該…」陷入選擇性障礙,不知道該把邏輯放哪邊

「把想做的事情在叫起B View 的那個 Moment 一起決定吧!!!」天空中出現一道光,從光裡傳出了一個聲音說著…

最近時常用到這種需求,在這邊整理一下用法

比方說我有四個畫面:帳單清單( Bills )、確認繳費( Confirm )、繳費中( Processing )、繳費成功( Success )、繳費失敗( Fails )

使用者在帳單清單中選擇他想要繳的項目之一,這時候我把資料明細帶入( Confirm )

( Confirm )裡會有兩個Button,一個是確定,一個是取消,當使用者按下確定之後,會顯示一段( Processing )的過場動畫

接著依照繳費成功或失敗的結果顯示對應的畫面

作法一:把實際上繳費的行為寫在( Confirm ),如果成功就顯示( Success );失敗就顯示( Fails )

優點:邏輯單純,好讀好理解。

缺點,畫面和邏輯綁太緊,彈性不夠。

作法二:在( Bills )把流程寫好,把該做的事放到各自對應的畫面預留的Function裡。

優點:流程有彈性,調整畫面邏輯比較方便。

缺點:架構上比較複雜,會花比較多的時間理解流程與設計精神。

因為這篇文章主要是針對 Closure ,所以會比較接近作法二的情況

比較關鍵的程式如下:

在 BillsViewController 裡面的某個按鈕去叫起( Confirm ),並指定這個按鈕要做的事情:

        let ConfirmVC : ConfirmViewController = UIStoryboard.init(name: kAlertStoryboard, bundle: nil).instantiateViewController(withIdentifier: "ConfirmVC") as! ConfirmViewController
        ConfirmVC.billData = BillData
        ConfirmVC.actionButtonHandler = {
            ConfirmVC.dismiss(animated: true, completion: nil)
            self.beginPaymentFlow(BillData: BillData)
        }
        ConfirmVC.cancelButtonHandler = {
            ConfirmVC.dismiss(animated: true, completion: nil)
        }
        
        self.presentOverCurrentContextViewController(ConfirmVC, animated: true, completion:nil)

當然,在 ConfirmViewController 裡面早已定義好相對應的 Handler 參數讓外頭塞 function:

    var billData : Bill?
    var actionButtonHandler : (() -> ())?
    var cancelButtonHandler : (() -> ())?

    @IBAction func actionButtonOnTapped(_ sender: Any) {
        self.actionButtonHandler!()
    }
    @IBAction func cancelButtonOnTapped(_ sender: Any) {
        self.cancelButtonHandler!()
    }

如果 Function 還要傳值進去的話也可以寫成這樣:

宣告:

var actionButtonHandler : ((String, Int) -> ())?

那麼定義的時候就變為:
        ConfirmVC.actionButtonHandler = { (name : String, age : Int)->() in
            print(name)
            print(age);
        }

叫用的時候自然就變成:

self.actionButtonHandler!("John",30)

以上,日後忘記了就來這邊回憶一下吧