Giới thiệu về Closures Framework
Closures là một thư viện Swift được thiết kế dành riêng cho nền tảng iOS, mang đến khả năng xử lý sự kiện thông qua closure thay vì sử dụng các pattern truyền thống như delegation hay target-action. Thư viện này mở rộng chức năng cho hầu hết các class trong UIKit và Foundation, giúp mã nguồn trở nên gọn gàng và dễ bảo trì hơn.
Vấn đề với Delegation Pattern truyền thống
Trong phát triển ứng dụng iOS, delegation là một pattern phổ biến nhưng tồn tại một số nhược điểm:
- Cần định nghĩa protocol và implement các method delegate
- Mã nguồn bị phân tán qua nhiều file
- Khó theo dõi luồng xử lý sự kiện
- Boilerplate code nhiều và lặp lại
Closures giải quyết như thế nào?
Thư viện cung cấp cơ chế callback trực tiếp thông qua closure, cho phép viết mã theo phong cách functional programming với khả năng chain methods liền mạch.
Xử lý sự kiện UI Controls
Thay vì sử dụng @IBAction hoặc addTarget, bạn có thể gắn handler trực tiếp:
let submitButton = UIButton()
submitButton.onTap { [weak self] in
self?.handleSubmit()
}
let toggleSwitch = UISwitch()
toggleSwitch.onChange { [weak self] isEnabled in
self?.updateSetting(enabled: isEnabled)
}
Gesture Recognizers
Thêm gesture trở nên đơn giản hơn nhiều:
let contentView = UIView()
contentView.addSwipeGesture(direction: .left) { [weak self] recognizer in
self?.navigateToPreviousScreen()
}
contentView.addLongPressGesture { recognizer in
if recognizer.state == .began {
print("Long press detected")
}
}
Làm việc với UITableView
Cung cấp hai cách tiếp cận: đơn giản hóa với collection binding hoặc linh hoạt với closure-based delegates:
Phương pháp 1 - Collection Binding:
struct Product {
let name: String
let price: Double
}
let products: [Product] = loadProducts()
tableView.bind(products, cellType: ProductCell.self) { product, cell, indexPath in
cell.configure(with: product)
}
Phương pháp 2 - Granular Control:
tableView.register(ProductCell.self, forCellReuseIdentifier: "ProductCell")
tableView
.setNumberOfRows { _ in
return self.products.count
}
.setConfigureCell { indexPath in
let cell = tableView.dequeueReusableCell(
withIdentifier: "ProductCell",
for: indexPath
) as! ProductCell
cell.configure(with: self.products[indexPath.row])
return cell
}
.setDidSelectRow { indexPath in
self.showProductDetail(at: indexPath.row)
}
.setHeightForRow { indexPath in
return indexPath.row == 0 ? 80 : 60
}
UICollectionView
Tương tự, UICollectionView cũng được hỗ trợ đầy đủ:
collectionView.register(PhotoCell.self, forCellWithReuseIdentifier: "PhotoCell")
collectionView
.setNumberOfItems { _ in
return self.photos.count
}
.setConfigureItem { indexPath in
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: "PhotoCell",
for: indexPath
) as! PhotoCell
cell.imageView.image = self.photos[indexPath.item]
return cell
}
.setDidSelectItem { indexPath in
self.openPhotoViewer(for: indexPath.item)
}
Tính năng nâng cao
UIImagePickerController
Đây là một trong những tính năng hữu ích nhất, loại bỏ hoàn toàn delegate pattern phức tạp:
let imagePicker = UIImagePickerController(
sourceType: .photoLibrary,
mediaTypes: [.image]
) { [weak self] result, picker in
switch result {
case .success(let media):
if let image = media.originalImage {
self?.profileImageView.image = image
}
case .failure(let error):
self?.showError(error.localizedDescription)
}
picker.dismiss(animated: true)
}
imagePicker.present(from: self)
UIAlertController
Tạo và present alert trở nên ngắn gọn:
let alert = UIAlertController(
title: "Xác nhận xóa",
message: "Bạn có chắc muốn xóa mục này?",
preferredStyle: .alert
)
alert.addAction(title: "Xóa", style: .destructive) { _ in
self.deleteItem()
}
alert.addAction(title: "Hủy", style: .cancel)
alert.present(from: self)
Cài đặt vào dự án
Swift Package Manager
Trong Xcode, chọn File → Add Packages... và nhập repository URL.
CocoaPods
Thêm vào Podfile:
pod 'Closures'
Carthage
Thêm vào Cartfile:
github "vhesener/Closures"
Manual
Kéo thả folder Sources vào project Xcode của bạn.
Lưu ý khi sử dụng
- Luôn sử dụng
[weak self]trong closure để tránh retain cycle - Thư viện tương thích từ iOS 8.0 trở lên
- Có thể kết hợp với delegation truyền thống trong cùng một project
Giấy phép
Dự án được phát hành dưới MIT License, cho phép sử dụng tự do trong cả dự án thương mại và cá nhân.