Các khóa học lập trình iOS Objective-C, lập trình iOS Swift và lập trình iOS Swift kết nối Web Service có sẵn toàn bộ mã nguồn, hướng dẫn chi tiết từng bước và được trình bày rất dễ hiểu.
Delegate và Block khác nhau ở điểm nào và dùng cái gì khi nào? Ở phần 1 tôi sẽ tập trung giới thiệu và phân tích Delegate. Sang phần 2 tôi sẽ so sánh Block với Delegate và cách chuyển từ Delegate sang Block trong một số trường hợp nên chuyển.
Delegate trong Objective-C là một pattern để đối tượng A ủy nhiệm đối tượng B làm hộ việc gì thông qua protocol mà đối tượng B phải tuân thủ (adopt protocol).
Ví dụ điển hình đó là class UITableView có 2 protocol UITableViewDelegate (chuyên hứng các sự kiện người dùng tương tác lên table view) và UITableViewDataSource (chuẩn bị dữ liệu cho table view). UITableView sẽ ủy nhiệm cho UIViewController hoặc UITableViewController thực hiện các hàm đề xuất trong 2 protocol UITableViewDelegate và UITableViewDataSource
UIViewController tuân thủ 2 protocol UITableViewDataSource và UITableViewDelegate. UITableView uỷ nhiệm cho UIViewController để cấu hình, chuẩn bị dữ liệu và hứng sự kiện tương tác của người dùng
Lợi điểm của Delegate
1- Dev thay vì phải subclass các View để hứng sự kiện, điền dữ liệu thì nay có thể ủy nhiệm để ViewController thực hiện việc này. Mô hình MVC trở nên rõ ràng hơn.
@interface ViewController: UIViewController <UITableViewDataSource, UITableViewDelegate>
2- Delegate được sử dụng như call back function khi lập trình asynchronous trong networking, ví dụ như UIViewController tuân thủ NSURLConnectionDataDelegate để hứng sự kiện dữ liệu từ Internet trả về. Đường truyền Internet không thể đảm bảo dữ liệu trả về ngay lập tức, do đó sử dụng delegate giúp ứng dụng không phải dừng ở main thread để đợi dữ liệu. Xem ví dụ này https://github.com/HaifaCarina/Preloader
@protocol NSURLConnectionDataDelegate <NSURLConnectionDelegate>
@optional
...
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
...
@end
3- Delegate và Protocol còn dùng để giảm tối đa sự liên kết quá cứng nhắc không cần thiết giữa các lớp. Lớp A có con trỏ đến lớp B, C, D, E. Rồi có thể B lại chứa con trỏ đến A, C, D, E. Để làm việc này, các class phải import các header lẫn nhau, tạo ràng buộc cứng, khiến chương trình khó nâng cấp, thay đổi tính năng.
Thay vào đó, A không cần biết B hay C mà chỉ cần giữ một con trỏ id delegate. Nếu B, C, … tuân thủ ProtocolX, id có thể trỏ tới B, C. Khi cần thiết A sẽ gọi [delegate doSomeThing] mà không gọi [objB doSomething], [objC doSomething].
Bất cập của Delegate
Cho đến bản iOS 5.x, Apple vẫn cấm việc lập trình viên để một đối tượng tự chọn delegate vào chính nó
self.delegate = self
Cách này khiến cho ứng dụng bị treo cứng đơ. Chỉ đến iOS 6.x Apple mới sửa lỗi và cho phép self.delegate = self
Trong bài “Xử lý lỗi crash khi tạo custom UITextView và đặt delegate bằng chính nó” tôi đã đề xuất cách sửa lỗi khi chạy trên iOS 5.x
Trong một số trường hợp, delegate không phải là lựa chọn tốt, ví dụ như trường hợp UIAlertViewDelegate. Khi một UIViewController tuân thủ UIAlertViewDelegate nhưng mở nhiều loại UIAlertView khác nhau, lúc này các phương thức thể hiện UIAlertViewDelegate sẽ phải bổ xung lệnh if then else hoặc switch để kiểm tra sự kiện nào do đối tượng UIAlertView nào gây ra. Code tại các phương thức này sẽ cồng kềnh khó bảo trì
@protocol UIAlertViewDelegate <NSObject>
@optional
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
...
@end
Nhiều lập trình viên đã đề xuất sử dụng block để thay thế delegate. Việc này diễn ra ở rất nhiều API khác nhau của Apple iOS. Bản thân Apple không thể sớm chiều loại bỏ delegate trong một số API vì số lượng code sử dụng API có thể đã rất lớn và khó thay đổi.
Tham khảo mã nguồn một ví dụ chuyển từ UIAlertViewDelegate sang UIAlertView+Block
Bình luận