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标记),也可以是必需的。
实现代理模式的步骤
实现代理模式通常涉及以下几个关键步骤:
- 定义协议: 明确委托者需要代理执行的操作。
- 在委托者中声明代理属性: 通常使用
weak var delegate: MyCustomViewDelegate?来避免循环引用。 - 在委托者中调用代理方法: 当特定事件发生时,委托者会通知其代理。
- 让代理遵循协议: 代理对象需要声明它遵循了该协议。
- 实现协议方法: 代理对象提供协议中定义的方法的具体实现。
例如,在一个自定义视图 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 自身则保持了高度的通用性。这种模式的优雅之处在于,它允许你轻松地替换代理,从而改变组件的行为,而无需修改组件本身的任何代码。这正是组件化设计的魅力所在!✨