プレーン言語でのSwiftデリゲートとコールバック。このデリゲートとは何ですか?コールバックはどのように機能しますか?

Swiftでは、UI(ユーザーインターフェイス)を学習するときに、遅かれ早かれ、誰もがデリゲートを使用する必要が生じます。すべてのガイドがそれらについて書いています、そしてあなたはそこに書かれているようにやっているようです、そしてそれはうまくいくようです、しかしそれがなぜそしてどのように働くのか、彼らの頭の中の誰もが最後に収まるわけではありません。個人的には、デリゲートはある種の魔法の言葉であり、プログラミング言語に直接組み込まれているとしばらく感じました(これらのガイドからの私の考えは非常に混乱していました)。それが何であるかを簡単に説明してみましょう。そして、デリゲートを理解すると、コールバックとは何か、そしてそれがどのように機能するかを理解するのがはるかに簡単になります。



ウェイターとシェフ



それで、コードに移る前に、特定のウェイターと何人かのシェフを想像してみましょう。ウェイターはテーブルでクライアントから注文を受けましたが、彼自身は料理の仕方がわからないので、料理人にそれについて尋ねる必要があります。彼は台所に行って料理人に「鶏肉を作って」と言うことができます。料理人は適切な道具(フライパン、オイル、火など)と調理スキルを持っています。料理人は料理を準備してウェイターに渡します。ウェイターはシェフが作ったものを受け取り、それをクライアントに持ってきます。



ここで、ウェイターがキッチンに駆け寄って、どの料理を注文したかを料理人に直接伝えることができない状況を想像してみましょう。彼らは彼を台所に入れさせない(例えば、そのような規則)か、台所が別の階にある(あなたは走るのに飽きる)。そして、通信する唯一の方法は、ミニエレベーターウィンドウを介することです。ウェイターはそこにメモを置き、ボタンを押すと、エレベーターはキッチンに行きます。惣菜で帰ってきます。覚えていますか?それでは、頭の中で状況を修正し、コードを使用して状況を再現し、トピックとの関連を理解してみましょう。



コードに転送しましょう



ウェイタークラスとクッククラスを作成します。簡単にするために、遊び場でこれを行いましょう:



import UIKit

//   
class Waiter {

    ///  "" -     .      ,  "private".
    private var order: String?

    ///  " ".
    func takeOrder(_ food: String) {
        print("What would you like?")
        print("Yes, of course!")
        order = food
        sendOrderToCook()
    }

    ///  "  ".     .  ?
    private func sendOrderToCook() {
        // ???    ?
    }

    ///  "  ".   .
    private func serveFood() {
        print("Your \(order!). Enjoy your meal!")
    }

}

//   
class Cook {

    ///  "".    .
    private let pan: Int = 1

    ///  "".    .
    private let stove: Int = 1

    ///  "".   .
    private func cookFood(_ food: String) -> Bool {
        print("Let's take a pan")
        print("Let's put \(food) on the pan")
        print("Let's put the pan on the stove")
        print("Wait a few minutes")
        print("\(food) is ready!")
        return true
    }

}


次に、それらのコピーを作成し(仕事に雇う)、ウェイターに注文を受け取るように依頼します(チキン):



//       ( ):
let waiter = Waiter()
let cook = Cook()

//     . ,   :
waiter.takeOrder("Chiken")


ウェイターはどのようにしてコックに今何を調理するかを伝えることができますか?



, , private. private, :



cook.cookFood(waiter.order!)
// 'cookFood' is inaccessible due to 'private' protection level
// 'order' is inaccessible due to 'private' protection level


«» , private . "" , ? : " , , ?"



"". . . "" " ":



protocol InterchangeViaElevatorProtocol {
    func cookOrder(order: String) -> Bool
}


, "", , . . , . : , .





, . ().



. , , " ". Xcode . Bool .



cookFood, .



extension Cook: InterchangeViaElevatorProtocol {
    func cookOrder(order: String) -> Bool {
        cookFood(order)
    }
}


" ". , , .



extension Waiter {
    var receiverOfOrderViaElevator: InterchangeViaElevatorProtocol? { return cook }
}


, . return cook.



-: , . .



, . , .



:



import UIKit

protocol InterchangeViaElevatorProtocol {
    func cookOrder(order: String) -> Bool
}

class Waiter {

    //     "   ".  ,        ,   .
    var receiverOfOrderViaElevator: InterchangeViaElevatorProtocol?

    var order: String?

    func takeOrder(_ food: String) {
        print("What would you like?")
        print("Yes, of course!")
        order = food
        sendOrderToCook()
    }

    private func sendOrderToCook() {
        // ???    ?
    }

    private func serveFood() {
        print("Your \(order!). Enjoy your meal!")
    }

}

//   
class Cook: InterchangeViaElevatorProtocol {

    private let pan: Int = 1
    private let stove: Int = 1

    private func cookFood(_ food: String) -> Bool {
        print("Let's take a pan")
        print("Let's put \(food) on the pan")
        print("Let's put the pan on the stove")
        print("Wait a few minutes")
        print("\(food) is ready!")
        return true
    }

    //  ,  ():
    func cookOrder(order: String) -> Bool {
        cookFood(order)
    }

}


private order ( ).



:



  1. :


//      :
let waiter = Waiter()
let cook = Cook()

//   :
waiter.takeOrder("Chiken")


, " " – .



//   ,   "   " -   :
waiter.receiverOfOrderViaElevator = cook


, , , .



" " :



//     "   "   :
waiter.receiverOfOrderViaElevator?.cookOrder(order: waiter.order!)


, !



/*
 What would you like?
 Yes, of course!
 Let's take a pan
 Let's put Chiken on the pan
 Let's put the pan on the stove
 Wait a few minutes
 Chiken is ready!
 */


« », .



«» , « », , .



    private func sendOrderToCook() {
        //   cookOrder   "   ":
        receiverOfOrderViaElevator?.cookOrder(order: order!)
    }


! receiverOfOrderViaElevator, . . delegate, . , , .



? «, – . – UI?»



delegate UI?



UI , «» «». , table view collection view. table view collection view : . . () «» («Delegate»).



, Delegable «». , , !



, – . . Waiter. () hireWaiter. (, -):



//   -
class Chief: InterchangeViaElevatorProtocol {

    private let pan: Int = 1
    private let stove: Int = 1

    private func cookFood(_ food: String) -> Bool {
        print("Let's take a pan")
        print("Let's put \(food) on the pan")
        print("Let's put the pan on the stove")
        print("Wait a few minutes")
        print("\(food) is ready!")
        return true
    }

    //  ,  ():
    func cookOrder(order: String) -> Bool {
        cookFood(order)
    }

    // -      :
    func hireWaiter() -> Waiter {
        return Waiter()
    }

}


- ( - hireWaiter):



//   - (-  ):
let chief = Chief()

// -  :
let waiter = chief.hireWaiter()

//   :
waiter.takeOrder("Chiken")


. , " " – -. .



//  ,   "   " -   -:
waiter.receiverOfOrderViaElevator = chief
//     "   "   :
waiter.receiverOfOrderViaElevator?.cookOrder(order: waiter.order!)


, .



. , -, , « » -.



class SmartChief: Chief {

    override func hireWaiter() -> Waiter {
        let waiter = Waiter()
        waiter.receiverOfOrderViaElevator = self //         
        return waiter
    }

}


SmartChief Chief .



, - (), . !



let smartChief = SmartChief()
let smartWaiter = smartChief.hireWaiter()
smartWaiter.takeOrder("Fish")
/*
 What would you like?
 Yes, of course we have Fish!
 Let's take a pan
 Let's put Fish on the pan
 Let's put the pan on the stove
 Wait a few minutes
 Fish is ready!
 */


:



  1. (), , , , - .
  2. «» .
  3. (, ) , ( )
  4. , self «» .


, «» , , .



. , ! .



(, callback). ? ,



, , «» . , . ? ?



(callback) – , . . .


-,



, - ( , ). , , : «- ! , !» , , . .



.



. . , String Bool. cookFood ! - - .



///   
class TalentedWaiter {

    var order: String?

    //      .  ,        String      Bool.
    var doEverything: ((String) -> Bool)?

    func takeOrder(_ food: String) {
        print("What would you like?")
        print("Yes, of course we have \(food)!")
        order = food
        //    -    :
        doOwnself()
    }

    private func doOwnself() -> Bool {
        //   ,    :
        if let doEverything = doEverything {
            let doOwnself = doEverything(order!)
            return doOwnself
        } else {
            return false
        }
    }

}


-. , , . , . , :



//    -
class LazyChief {

    private let pan: Int = 1
    private let stove: Int = 1

    private func cookFood(_ food: String) -> Bool {
        print("I have \(pan) pan")
        print("Let's put \(food) on the pan!")
        print("I have \(stove) stove. Let's put the pan on the stove!")
        print("Wait a few minutes...")
        print("\(food) is ready!")
        return true
    }

    //    :
    func hireWaiter() -> TalentedWaiter {
        let talentedWaiter = TalentedWaiter()

        //     .       ,       cookFood:
        talentedWaiter.doEverything = { order in
            self.cookFood(order)
        }
        return talentedWaiter
    }

}


-, , , :



let lazyChief = LazyChief()
let talentedWaiter = lazyChief.hireWaiter()
talentedWaiter.takeOrder("Meat")
/*
 What would you like?
 Yes, of course we have Meat!
 I have 1 pan
 Let's put Meat on the pan!
 I have 1 stove. Let's put the pan on the stove!
 Wait a few minutes...
 Meat is ready!
 */


, , «» .



, , . , , ().

– . , self , - , .



[weak self] in . , !



talentedWaiter.doEverything = { [weak self] order in
            self!.cookFood(order)
        }


. , . !



GitHub




All Articles