使用回撥閉包(塊)傳回資料

這個主題是 iOS 開發中的一個經典問題,其解決方案與其他已經顯示的示例不同。在這個例子中,我將展示另一個日常用途:使用 closure 通過將此頁面上的 delegate pattern 示例調整為回撥 closure 來傳遞資料!

這個方法優於 delegate pattern 的一件事是代替在兩個不同的地方拆分設定程式碼(看看這個頁面上的代表示例,prepareForSegueuserDidEnterInformation)而不是將它們聚集在一起(僅在 prepareForSegue 中,我將展示它)

從第二檢視控制器開始

我們必須弄清楚如何使用回撥,然後我們可以編寫它,這就是為什麼我們從第二個檢視控制器開始,因為它是我們使用回撥的地方:當我們得到新的文字輸入時,我們使用 callback 的引數作為媒介呼叫我們的回撥把資料傳回第一個 ViewController,注意我說使用回撥的引數,這是非常重要的,新手(因為我)總是忽略這一點,不知道從哪裡開始正確編寫回撥閉包

所以在這種情況下,我們知道我們的回撥只帶一個引數:text 和它的型別是 String,讓我們宣告它並使它成為屬性,因為我們需要從我們的第一個檢視控制器填充

我只評論所有的 delegate 部分,並保留它進行比較

class SecondViewController: UIViewController {

    //weak var delegate: DataEnteredDelegate? = nil
    var callback: ((String?)->())?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        //delegate?.userDidEnterInformation(textField.text!)
        callback?(input.text)
        
        self.navigationController?.popViewControllerAnimated(true)
    }
}

完成第一個檢視控制器

所有你需要做的就是傳遞迴調閉包,我們完成了,因為我們已經在第二個檢視控制器中設定了封閉將為我們做未來的工作

看看它與 delegate pattern 相比如何縮短我們的程式碼

//no more DataEnteredDelegate
class FirstViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            //secondViewController.delegate = self
            secondViewController.callback = { text in self.label.text = text }
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    //func userDidEnterInformation(info: String) {
    //    label.text = info
    //}
}

而在最後,也許有人會因為我們只在一種方式中傳遞資料(在這種情況下是封閉)而感到困惑,從第一個檢視控制器到第二個,沒有直接從第二個檢視控制器回來,我們怎麼能將其視為溝通工具?也許你真的應該執行它並自己證明,我會說它的引數,它是回撥閉包的引數傳遞資料!