iOS – 委托(Delegates)(长文讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在 iOS 开发中,委托(Delegates) 是一种核心设计模式,广泛应用于系统框架和自定义功能中。它通过协议(Protocol)和回调机制,实现了对象间高效、灵活的通信。对于编程初学者来说,委托模式可能显得抽象难懂;而对于中级开发者,则需要掌握其进阶用法和最佳实践。本文将从基础概念逐步深入,结合代码示例和实际场景,帮助读者全面理解委托模式的原理与应用。


委托模式的定义与核心思想

什么是委托?

委托(Delegate)是一种对象间协作的编程模式,允许一个对象(委托对象)将某些任务或决策委托给另一个对象(委托代理)。

  • 核心概念
    • 委托对象(Delegator):需要执行任务或获取信息的对象。
    • 委托代理(Delegate):接收委托并提供具体实现的对象。
    • 协议(Protocol):定义委托代理需要实现的方法或属性。

为什么需要委托?

委托模式通过解耦对象间的直接依赖,实现了代码的复用和扩展性。例如,UIKit 中的 UITableView 通过委托协议 UITableViewDelegate,让外部对象负责数据源管理和交互逻辑,而非自己硬编码这些逻辑。

形象比喻:委托就像“中介”

想象一个快递代收点:快递公司(委托对象)将包裹的签收工作委托给代收点(委托代理)。快递公司无需关心代收点的具体操作,只需遵循协议(如“签收后返回回执”)。这种分工使双方职责清晰,系统更灵活。


委托模式的实现步骤

1. 定义协议(Protocol)

协议是委托的基础,它声明了委托代理需要实现的方法或属性。

protocol NetworkDelegate: AnyObject {  
    func didReceive(response: String)  
    func didFailWithError(error: Error)  
}  

2. 在委托对象中声明委托属性

委托对象需持有委托代理的弱引用(weak),避免循环引用。

class NetworkManager {  
    weak var delegate: NetworkDelegate?  
    // ...  
}  

3. 实现委托方法

委托代理需遵守协议,并实现协议中定义的方法。

class ViewController: UIViewController, NetworkDelegate {  
    func didReceive(response: String) {  
        print("Received response: \(response)")  
    }  
    func didFailWithError(error: Error) {  
        print("Error: \(error.localizedDescription)")  
    }  
}  

4. 触发委托方法

当委托对象需要通知代理时,直接调用协议方法。

// 在 NetworkManager 中调用  
delegate?.didReceive(response: "Success!")  

实战案例:UITableView 的委托模式

案例背景

UITableView 的核心功能依赖于两个协议:UITableViewDataSourceUITableViewDelegate。通过委托模式,开发者可以灵活控制表格的行数、单元格样式和交互行为。

实现步骤

1. 遵守协议并设置委托

在视图控制器中声明遵守协议,并将表格的委托属性指向自身。

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {  
    @IBOutlet weak var tableView: UITableView!  

    override func viewDidLoad() {  
        super.viewDidLoad()  
        tableView.dataSource = self  
        tableView.delegate = self  
    }  
}  

2. 实现数据源方法

通过 UITableViewDataSource 协议,定义表格的数据逻辑。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {  
    return 10 // 返回行数  
}  

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {  
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)  
    cell.textLabel?.text = "Row \(indexPath.row)"  
    return cell  
}  

3. 实现委托方法

通过 UITableViewDelegate 协议,定义单元格的交互行为,例如点击事件。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {  
    print("Selected row \(indexPath.row)")  
    tableView.deselectRow(at: indexPath, animated: true)  
}  

案例总结

通过委托模式,UITableView 将数据展示和交互逻辑的控制权交给外部对象(如视图控制器),既保证了组件的通用性,又提高了代码的可维护性。


进阶技巧与常见问题

1. 强引用与弱引用的陷阱

委托属性必须使用 weak 关键字,否则会导致循环引用。例如:

// 错误写法:强引用导致内存泄漏  
var delegate: NetworkDelegate! // 避免使用强引用  

// 正确写法  
weak var delegate: NetworkDelegate?  

2. 可选方法与必需方法

在协议中,可以通过 @optional@required 标记方法的可选性。但在 Swift 中,默认所有方法均为必需,需通过 @objc optional 标记可选方法(仅适用于 @objc 协议)。

@objc protocol CustomDelegate {  
    func requiredMethod()  
    @objc optional func optionalMethod()  
}  

3. 多个委托的处理

若一个对象需要同时遵循多个协议,可使用协议组合:

protocol DelegateA { ... }  
protocol DelegateB { ... }  

class MyClass: DelegateA, DelegateB { ... }  

委托模式的扩展与最佳实践

1. 自定义委托场景

在自定义类中实现委托模式,例如创建一个网络请求工具类:

protocol NetworkServiceDelegate: AnyObject {  
    func didFinishLoading(data: Data)  
}  

class NetworkService {  
    weak var delegate: NetworkServiceDelegate?  
    func fetchData() {  
        // 模拟网络请求  
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {  
            self.delegate?.didFinishLoading(data: Data())  
        }  
    }  
}  

2. 使用闭包替代委托

对于简单场景,闭包(Closure)可能比委托更简洁。但委托更适合复杂或长期交互的场景。

class NetworkService {  
    var completionHandler: ((Data) -> Void)?  
    func fetchData(completion: ((Data) -> Void)?) {  
        completionHandler = completion  
        // ...  
        completionHandler?(Data())  
    }  
}  

3. 遵循 Apple 的设计规范

  • 协议名称以 Delegate 结尾,如 UITableViewDelegate
  • 方法名以 delegate 开头,明确传递上下文对象(如 tableView(_:didSelectRowAt:))。

结论

iOS – 委托(Delegates) 是 iOS 开发中不可或缺的设计模式,它通过协议和回调机制,实现了对象间松耦合、高扩展的通信。无论是系统框架如 UITableView,还是自定义功能如网络请求,委托模式都能帮助开发者编写更清晰、可维护的代码。

通过本文的学习,读者应能掌握委托模式的实现原理、常见问题及最佳实践。在实际开发中,建议结合具体场景灵活运用委托模式,同时注意内存管理和协议设计的规范性,以提升代码质量和开发效率。


关键词布局:iOS – 委托(Delegates)、委托模式、协议、委托代理、回调机制、UITableViewDelegate、弱引用、闭包替代委托、内存泄漏、协议组合

最新发布