在 iOS 开发中,Handler(处理者) 是一种常见的设计模式,用于解耦代码逻辑、异步处理任务或事件回调。它通常以闭包(Closure)、代理(Delegate)或目标-动作(Target-Action)的形式实现,帮助开发者将复杂逻辑拆分为可复用的模块。以下是几个典型场景的代码示例和优化思路:
1. 闭包(Closure)作为 Handler
场景:网络请求完成后,通过闭包回调处理结果,避免阻塞主线程。
优化前(嵌套回调,代码臃肿)
func fetchUserData(completion: @escaping (User?, Error?) -> Void) {
URLSession.shared.dataTask(with: URL(string: "https://api.example.com/user")!) { data, _, error in
if let error = error {
completion(nil, error)
return
}
guard let data = data else {
completion(nil, NSError(domain: "InvalidData", code: 0))
return
}
do {
let user = try JSONDecoder().decode(User.self, from: data)
completion(user, nil)
} catch {
completion(nil, error)
}
}.resume()
}
// 调用时嵌套回调
fetchUserData { user, error in
if let error = error {
print("Error: (error)")
} else if let user = user {
print("User: (user.name)")
}
}
优化后(提取 Handler 逻辑)
// 定义通用的 Result Handler
typealias ResultHandler<T> = (Result<T, Error>) -> Void
func fetchUserData(completion: @escaping ResultHandler<User>) {
let url = URL(string: "https://api.example.com/user")!
URLSession.shared.dataTask(with: url) { data, _, error in
let result: Result<User, Error> = Result {
guard let data = data else { throw error ?? NSError(domain: "Unknown", code: 0) }
return try JSONDecoder().decode(User.self, from: data)
}
DispatchQueue.main.async { completion(result) } // 切换到主线程
}.resume()
}
// 调用时更清晰
fetchUserData { result in
switch result {
case .success(let user): print("User: (user.name)")
case .failure(let error): print("Error: (error)")
}
}
优化点:
- 使用
Result类型统一处理成功/失败,减少嵌套。 - 提取
ResultHandler类型别名,提升可读性。 - 确保回调在主线程执行(UI 更新安全)。
2. 代理(Delegate)作为 Handler
场景:表格视图(UITableView)的数据源和事件处理通过代理解耦。
优化前(直接实现代理方法,逻辑分散)
class ViewController: UIViewController, 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
}
}
优化后(提取 Handler 类)
// 定义 Handler 协议
protocol TableViewHandlerDelegate: AnyObject {
func configureCell(_ cell: UITableViewCell, at indexPath: IndexPath)
}
class TableViewHandler: NSObject, UITableViewDataSource {
weak var delegate: TableViewHandlerDelegate?
private let rowCount: Int
init(rowCount: Int = 10) {
self.rowCount = rowCount
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowCount
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
delegate?.configureCell(cell, at: indexPath)
return cell
}
}
// 在 ViewController 中使用
class ViewController: UIViewController, TableViewHandlerDelegate {
@IBOutlet weak var tableView: UITableView!
private let handler = TableViewHandler(rowCount: 10)
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = handler
handler.delegate = self
}
func configureCell(_ cell: UITableViewCell, at indexPath: IndexPath) {
cell.textLabel?.text = "Optimized Row (indexPath.row)"
}
}
优化点:
- 将数据源逻辑移至
TableViewHandler,减少ViewController的职责。 - 通过协议(Delegate)灵活定制单元格配置。
- 便于单元测试(可单独测试
TableViewHandler)。
3. 目标-动作(Target-Action)作为 Handler
场景:按钮点击事件通过 @objc 方法处理,但可优化为闭包。
优化前(传统 Target-Action)
class ViewController: UIViewController {
@objc func buttonTapped() {
print("Button tapped!")
}
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
}
优化后(闭包封装)
extension UIButton {
func onTap(_ handler: @escaping () -> Void) {
self.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
// 使用关联对象存储闭包(需导入 Objective-C 运行时)
objc_setAssociatedObject(self, &AssociatedKeys.tapHandler, handler, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
@objc private func handleTap() {
if let handler = objc_getAssociatedObject(self, &AssociatedKeys.tapHandler) as? () -> Void {
handler()
}
}
}
private struct AssociatedKeys {
static var tapHandler = "tapHandler"
}
// 使用
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.onTap { print("Closure-based tap handler!") }
}
}
优化点:
- 避免
@objc方法污染ViewController。 - 直接通过闭包定义事件逻辑,更符合 Swift 风格。
总结
| Handler 类型 | 适用场景 | 优化收益 |
|---|---|---|
| 闭包(Closure) | 异步回调、轻量级事件处理 | 减少嵌套,统一错误处理 |
| 代理(Delegate) | 复杂交互、多方法协作 | 解耦逻辑,提升可测试性 |
| 目标-动作(闭包封装) | UI 事件处理 | 避免 @objc,代码更简洁 |
通过合理使用 Handler 模式,可以显著提升代码的可读性、可维护性和复用性,尤其在异步编程和模块化设计中效果显著