在 Swift 中使用委托模式?
委托总是让我感到困惑,直到我意识到委托只是为另一个类做一些工作的类。这就像有另一个人帮你做所有你不想自己做的肮脏工作。
我写了一个小故事来说明这一点。如果你喜欢的话可以在Playground中阅读。
从前有座山...
// MARK: Background to the story // A protocol is like a list of rules that need to be followed. protocol OlderSiblingDelegate: class { // The following command (ie, method) must be obeyed by any // underling (ie, delegate) of the older sibling. func getYourNiceOlderSiblingAGlassOfWater() } // MARK: Characters in the story class BossyBigBrother { // I can make whichever little sibling is around at // the time be my delegate (ie, slave) weak var delegate: OlderSiblingDelegate? func tellSomebodyToGetMeSomeWater() { // The delegate is optional because even though // I'm thirsty, there might not be anyone nearby // that I can boss around. delegate?.getYourNiceOlderSiblingAGlassOfWater() } } // Poor little sisters have to follow (or at least acknowledge) // their older sibling's rules (ie, protocol) class PoorLittleSister: OlderSiblingDelegate { func getYourNiceOlderSiblingAGlassOfWater() { // Little sis follows the letter of the law (ie, protocol), // but no one said exactly how she had to respond. print("Go get it yourself!") } } // MARK: The Story // Big bro is laying on the couch watching basketball on TV. let bigBro = BossyBigBrother() // He has a little sister named Sally. let sally = PoorLittleSister() // Sally walks into the room. How convenient! Now big bro // has someone there to boss around. bigBro.delegate = sally // So he tells her to get him some water. bigBro.tellSomebodyToGetMeSomeWater() // Unfortunately no one lived happily ever after... // The end.
回顾一下,制作和使用委托模式有三个关键部分:
- 协议 定义了工作所需的内容
- 老板类 有一个委托变量,它用来告诉工人类要做什么
- 工人类 采纳协议并按要求完成工作
现实生活
与上述Bossy Big Brother故事相比,委托通常用于以下实际应用:
- 通信:一个类需要发送一些信息到另一个类。
- 代码示例1:从一个视图控制器发送数据到另一个视图控制器
- 代码示例2:从自定义键盘发送文本输入到一个文本字段
- 自定义:一个类想要允许另一个类对其进行自定义。
很棒的一点是,除了委托类符合所需协议之外,这些类之前不需要知道任何关于彼此的信息。
我强烈推荐阅读以下两篇文章。它们帮助我更好地理解委托,甚至比文档更好。
还有一个注意事项
引用它们不拥有的其他类的委托应使用weak
关键字以避免强引用循环。 有关更多详细信息,请参见此答案。
下面是有关两个视图控制器之间委托的一些帮助:
步骤1:在您将删除/将发送数据的UIViewController中创建一个协议。
protocol FooTwoViewControllerDelegate:class { func myVCDidFinish(_ controller: FooTwoViewController, text: String) }
步骤2:在发送类中声明委托(即UIViewcontroller)
class FooTwoViewController: UIViewController { weak var delegate: FooTwoViewControllerDelegate? [snip...] }
步骤3:在类方法中使用委托将数据发送到采用该协议的任何方法作为接收方。
@IBAction func saveColor(_ sender: UIBarButtonItem) { delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error }
步骤4:在接收类中采用协议
class ViewController: UIViewController, FooTwoViewControllerDelegate {
步骤5:实现委托方法
func myVCDidFinish(_ controller: FooTwoViewController, text: String) { colorLabel.text = "The Color is " + text controller.navigationController.popViewController(animated: true) }
步骤6:在prepareForSegue:中设置委托
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "mySegue" { let vc = segue.destination as! FooTwoViewController vc.colorString = colorLabel.text vc.delegate = self } }
理论上应该可以运作。当然,这只是代码片段,但应该可以让您了解到。如果您对此代码的详细解释感兴趣,可以在这里查看我的博客文章:
如果您想了解委托的内部实现原理,可以在这里阅读我的文章: