Ba cách để truyền data từ Model đến Controller
Nếu bạn là một iOS developer hoặc là developer nói chung, bạn chắn chắn sẽ phải giải quyết vấn đề này trong hầu hết dự án: Làm thế nào để truyền data từ Model đến Controller
Tôi sẽ mô tả 3 cách cơ bản để truyền data trở lại cho Controller của bạn:
- Sử dụng Callbacks
- Sử dụng Delegation
- Sử dụng Notifications
Chúng ta sẽ đi qua lần lượt khái niệm của 3 cách trên, sau đó là ví dụ step-by-step. Đến cuối bài này bạn sẽ có thể chọn cách nào phù hợp nhất cho dự án của bạn.
Bắt đầu, chúng ta sẽ tạo 1 project cơ bản có ViewController và DataModel. Tại bước này, không quan trọng về nguồn data của bạn. Nó có thể là JSON file hay image nằm trên thư mục của app, CoreData hoặc một phản hồi HTTP. Trong mọi trường hợp, một khi bạn nhận data trong DataModel, bạn cần làm cách nào đó để truyền data này sang ViewController.
Vì vậy, bạn tạo ra 2 class: ViewController và DataModel.
1 |
|
Phần 1. Dùng Callback như là Completion Handler
Cách này rất dễ để cài đặt. Đầu tiên, chúng ta cần tạo ra 1 method requestData, nó nhận tham số là 1 completion (a block)
1 |
|
Bên trong requestData, chúng ta chạy code để yêu cầu data từ một nguồn nào đó.
1 |
|
Tất cả những gì chúng ta cần làm bây giờ là gọi method completion với tham số là data vừa mới nhận được.
1 |
|
Bước tiếp theo là tạo ra một instance của DataModel trong class ViewController và gọi method requestData. Trong completion, chúng ta gọi một private method useData:
1 |
|
Và bây giờ bạn có data trong ViewController, trong khi tất cả code liên quan data đều nằm ở class DataModel. Nếu bạn build và run project, bạn sẽ thấy data được in ra trong log.
Phần 1.5. Sử dụng Callback như là một class property
Một cách khác cũng sử dụng callback để giao tiếp với ViewController là tạo ra một callback như một DataModel property.
1 |
|
Bây giờ, bên trong method dataRequest, thay vì sử dụng completion handler, chúng ta có thể sử dụng callback này:
1 |
|
Để sử dụng callback này trong class ViewController, chúng ta chỉ cần gán method cho nó (sử dụng weak self):
1 |
|
Bạn có thể tạo ra nhiều callback property (onDataUpdate, onHTTPError, …). Tất cả callback được sử dụng tùy ý, nếu bạn không cần xử lý gì trên onHTTPError, đơn giản là bạn đừng sử dụng callback này. Đây là những điểm mạnh so với cách sử dụng trước đó.
Phần 2. Delegation
Delegation là cách phổ biến nhất để giao tiếp giữa DataModel và ViewController.
1 |
|
Bây giờ bạn cần tạo weak delegate trong DataModel:
1 |
|
Để gọi delegate, chúng ta sử dụng cách tương tự như cách callback:
1 |
|
Tạo ra một instance của DataModel trong ViewController, gán delegate của DataModel cho ViewController, và gọi method requestData:
1 |
|
Bước cuối cùng, tạo một extension của ViewController, nó kế thừa protocol DataModelDelegate và sử dụng delegate method didRecieveDataUpdate.
1 |
|
So sánh với cách dùng callback, mô hình delegation dễ dàng tái sử dụng hơn trên các ứng dụng: bạn có thể tạo một class cơ bản và nó tuân theo protocol. Tuy nhiên, delegation là khó khăn hơn khi thực hiện: bạn cần tạo một protocol, thiết lập các method trong protocol, tạo ra delegate property, gán delegate cho ViewController, và làm cho ViewController phù hợp với protocol. Ngoài ra, mặc định là delegate phải thực hiện mọi method trong protocol.
Một lần nữa, build và run project bạn sẽ thấy data được in ra trong log.
Phần 3. Notification
Trong khi 2 cách trên được sử dụng rất phổ biến, cách notification này thì không rõ ràng.
Dưới đây là một trong những hoàn cảnh cụ thể, nơi mà bạn có thể sử dụng notification để giao tiếp giữa DataModel và ViewController.
Ví dụ: nếu bạn cần lấy nhiều hình ảnh của user được lưu trữ cục bộ và sử dụng chúng trong nhiều ViewController, sử dụng delegation sẽ đòi hỏi mọi ViewController phải tuân theo protocol.
Đầu tiên, chúng ta sửa đổi DataModel và tạo nó thành một singleton class.
1 |
|
Tiếp theo, chúng ta thêm biến cục bộ cho DataModel, nó sẽ lưu data của bạn:
1 |
|
Cuối cùng, chúng ta thực hiện method requestData như trước đó:
1 |
|
Một khi chúng ta nhận được data trong requestData, chúng ta lưu nó trong biến cục bộ data:
1 |
|
Sau khi chúng ta cập nhật data, chúng ta muốn gửi một notification. Cách tốt nhất để làm điều này là sử dụng một property observer. Thêm property observer didSet vào biến data:
1 |
|
Trước khi chúng ta gửi một notification, hãy tạo ra một cái tên ý nghĩa cho nó. Chúng ta sẽ tạo một string literal bên ngoài của class DataModel:
1 |
|
Bây giờ chúng ta đã sẵn sàng để gửi một notification:
1 |
|
Dưới đây là những gì xảy ra phía sau code này: property observer (giống như tên của nó) sẽ quan sát bất kỳ sự thay đổi nào trong variable. Khi những thay đổi xuất hiện, chúng ta sẽ gửi một notification. Bây giờ chúng ta chỉ cần thêm một listener ở mọi nơi mà ViewController sử dụng data này.
1 |
|
Bây giờ các observer sẽ lắng nghe bất kỳ thông tin cập nhật nào trong DataModel và gọi method getDataUpdate cho mọi sự thay đổi. Hãy thực hiện method này:
1 |
|
Trong method này chúng ta đọc property DataModel.sharedInstance.data. Lưu ý rằng chúng ta không tạo ra một instance cục bộ của DataModel ở đây. Bởi vì, DataModel là một class singleton, chúng ta có thể truy cập method và property của nó bằng cách sử dụng sharedInstance.
Khi bạn làm việc với các notification, bạn nên nhớ 1 điều: bạn cần phải loại bỏ observer khi bạn không cần nó để lắng nghe các notification nữa. Nói cách khác, chúng ta cần chắc rằng NotificationCenter không quản lý observer mà bạn không sử dụng nữa. Để làm điều này, chúng ta cần loại bỏ các observer khi ViewController deallocated.
1 |
|
Trong một số tình huống, bạn không muốn một observer lắng nghe notification nếu ViewController này vẫn còn trong Navigation Stack nhưng mà không thấy được. Ví dụ, khi bạn trình diễn ViewController thứ 2 đè lên ViewController thứ 1, cập nhật data cho cái nằm phía dưới là lãng phí tài nguyên. Trong trường hợp này, bạn có thể thêm observer ở viewWillAppear và loại bỏ nó ở viewWillDisappear. Điều này sẽ đảm bảo rằng ViewController của bạn chỉ lắng nghe notification khi nó hiển thị trên màn hình.
Bước cuối cùng là để gọi method requestData, sử dụng sharedInstance của DataModel:
1 |
|
Build và run project kết quả sẽ giống như các lần chạy trước.
Đây là 3 cách cơ bản tôi sử dụng khi truyền data trong project.
Bạn có sử dụng bất kỳ kỹ thuật nào khác để truyền data? Hãy để lại nhận xét/câu hỏi/ý kiến/lời khuyên bên dưới.