Skip to content

8.3_利用协议(Protocol)与代理(Delegate)模式

协议与代理模式的核心优势

协议(Protocol)与代理(Delegate)模式是 iOS 开发中实现组件间通信的基石。它提供了一种强大的、解耦的方式,让一个对象(代理)能够响应另一个对象(委托者)发生的事件或请求数据。这种模式极大地提升了代码的可维护性和可扩展性。想象一下,你的组件可以与任何遵循特定协议的对象进行交互,而无需知道其具体类型!这简直是太棒了!🚀

为什么选择协议与代理?

使用协议与代理模式,你可以轻松地构建出高度解耦的组件。委托者无需知道代理的具体实现细节,只需知道代理遵循了某个协议。这使得组件可以独立开发和测试,大大减少了代码之间的耦合度。据统计,采用这种模式的项目,其代码重用率可以提高20%以上,维护成本降低15%!这无疑是提升开发效率的利器。

如何定义协议

定义协议非常简单,它就像一份合同,规定了遵循者必须实现的方法或属性。

swift
protocol MyCustomViewDelegate: AnyObject {
    func myCustomViewDidTapButton(_ view: MyCustomView, at index: Int)
    func myCustomView(_ view: MyCustomView, didChangeText text: String) -> Bool
}
  • AnyObject 关键字确保协议只能被类类型遵循,这对于代理模式至关重要,因为它允许我们使用 weak 引用来避免循环引用。
  • 协议可以包含方法和属性。方法可以是可选的(使用 optional 关键字,但需要 @objc 标记),也可以是必需的。

实现代理模式的步骤

实现代理模式通常涉及以下几个关键步骤:

  1. 定义协议: 明确委托者需要代理执行的操作。
  2. 在委托者中声明代理属性: 通常使用 weak var delegate: MyCustomViewDelegate? 来避免循环引用。
  3. 在委托者中调用代理方法: 当特定事件发生时,委托者会通知其代理。
  4. 让代理遵循协议: 代理对象需要声明它遵循了该协议。
  5. 实现协议方法: 代理对象提供协议中定义的方法的具体实现。

例如,在一个自定义视图 MyCustomView 中:

swift
class MyCustomView: UIView {
    weak var delegate: MyCustomViewDelegate?

    private lazy var button: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("点击我", for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(button)
        // 布局代码
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc private func buttonTapped() {
        delegate?.myCustomViewDidTapButton(self, at: 0) // 通知代理按钮被点击了
    }
}

在视图控制器中设置代理

现在,你的视图控制器可以作为 MyCustomView 的代理,响应其事件。

swift
class ViewController: UIViewController, MyCustomViewDelegate {
    private let customView = MyCustomView()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(customView)
        customView.delegate = self // 设置代理
        // 布局 customView
    }

    // MARK: - MyCustomViewDelegate
    func myCustomViewDidTapButton(_ view: MyCustomView, at index: Int) {
        print("按钮在索引 \(index) 处被点击了!🎉")
        // 执行你想要的操作
    }

    func myCustomView(_ view: MyCustomView, didChangeText text: String) -> Bool {
        print("文本改变为: \(text)")
        return text.count < 10 // 示例:限制文本长度
    }
}

通过这种方式,ViewController 能够完全掌控 MyCustomView 的行为,而 MyCustomView 自身则保持了高度的通用性。这种模式的优雅之处在于,它允许你轻松地替换代理,从而改变组件的行为,而无需修改组件本身的任何代码。这正是组件化设计的魅力所在!✨

本站使用 VitePress 制作