• Home
  • |
  • Hướng dẫn mô hình MVVM trong ios kỳ 2: Ví dụ

Tháng Mười 3, 2019

Hướng dẫn mô hình MVVM trong ios kỳ 2: Ví dụ

Download source sample tại đây.

Xem tổng quan và nội dung của series tại đây.

Ở bài trước mình đã trình bày lý thuyết sơ lược về mô hình MVVM trong ios. Tuy nhiên nếu chỉ nói lý thuyết suông suông thì chắc chắn tất cả chúng ta đều khó hình dung được.

Cho nên hôm nay chúng ta sẽ làm một demo đơn giản bằng mô hình MVVM. Thông qua hướng dẫn này các bạn có thể tự mình thiết lập mô hình MVVM ở mức cơ bản.

Mục tiêu của demo

Mục tiêu của demo đó là mình sẽ làm một màn hình đơn giản. Trong màn hình này gồm có:

  • 1 Label dùng để hướng dẫn
  • 1 switch. Switch này đã disable tap.
  • 1 button. Khi tap vào button thì sẽ gọi http request tới 1 api nào đó. Nếu thành công thì sẽ đổi trạng thái switch từ on sang off và ngược lại.

Sau đây là ảnh gif minh hoạ cho demo chúng ta sắp làm:

Thực hiện

Tải source project

Đầu tiên, các bạn hãy tải mình có để ở đầu bài.

Chạy project trên simulator, bạn sẽ thấy màn hình hiện lên như sau:

OK, bây giờ bạn hãy quay lại Xcode, đây là cấu trúc của project:

Trong project này chỉ có 1 màn hình đơn giản là SampleViewController. Kèm theo đó là một IBOutlet dành cho UISwitch và IBAction để handle button tap.

Ý tưởng thực hiện

Để điều khiển được logic của ViewController, chúng ta cần ViewModel. ViewModel sẽ được tạo và kết hợp với SampleViewController như sau:

Trong đó:

  • SampleViewController nắm giữ SampleViewModel thông qua thuộc tính ViewModel. SampleViewController sẽ gọi hàm xử lý logic từ SampleViewModel mỗi khi UIButton được tap.
  • SampleViewController sẽ data binding và lắng nghe (observe) sự kiện từ SampleViewModel mỗi khi thuộc tính isOn thay đổi và update vào trạng thái của switch tương ứng.
  • Lưu ý đường nét đứt từ SampleViewModel đến SampleViewController ở đây có ý nghĩa là SampleViewModel sẽ trigger event khi isOn thay đổi. Rồi SampleViewController hay bất kỳ đối tượng nào khác bắt sự kiện này cũng đc, SampleViewModel không quan tâm. Hay nói đơn giản là: SampleViewModel không hề biết gì về SampleViewController (xem lại nội dung của bài trước).

Ok ý tưởng đã có, giờ thì bắt tay vào làm thôi! 😃

Tạo ViewModel

Đầu tiên vào menu của Xcode, click vào File > New File > Swift File. Nhập tên file là SampleViewModel.

Trong file SampleViewModel, chèn đoạn code như sau:

import Bond // 1
class SampleViewModel { // 2
    // 3
    var isOn: Observable = Observable(true)
}

Trong đó:

  1. Import FrameWork Bond để sử dụng cho Data Binding. Sẽ được đề cập sau.
  2. Khai báo SampleViewModel dùng cho tầng ViewModel.
  3. Khai báo thuộc tính isOn dùng để điều khiển trạng thái bật / tắt của UISwitch trong SampleViewController. Để SampleViewController có thể lắng nghe (observe) ViewModel. Chúng ta sử dụng framework Bond để tích hợp DataBinding vào ViewModel. Bằng cách bọc kiểu dữ liệu isOn bằng Observable.

Bạn có thể thấy khi build thử Xcode sẽ báo lỗi No such module ‘Bond’. Đó là do chúng ta chưa cài đặt thư viện Bond vào.

Để cài đặt, mở file PodFile và chèn đoạn code sau dưới dòng comment # Pods for MVVM_Sample:

pod ‘Bond’

Mở ứng dụng Terminal lên, cd đến thư mục gốc (root) của project và chạy câu lệnh:

pod install

Lúc này khi chạy thử lại sẽ chạy được bình thường

Input ViewModel vào ViewController

Vào class SampleViewController, ngay trước hàm viewDidLoad chèn đoạn code như sau để khai báo ViewModel cho ViewController quản lý:

private let viewModel: SampleViewModel = SampleViewModel()

Binding ViewModel vào ViewController

Trong hàm viewDidLoad, chúng ta thêm đoạn code như sau:

viewModel.isOn.observeOn(.main).observeNext { (value: Bool) in
    self.switch.setOn(value, animated: true)
}.dispose(in: bag)

Ý nghĩa của đoạn code trên tương đối đơn giản: ViewController sẽ quan sát thuộc tính isOn của ViewModel để mỗi khi có sự thay đổi thì sẽ update trạng thái của UISwitch tương ứng

Khai báo action cho ViewModel

OK như vậy chúng ta đã Data Binding được thuộc tính isOn vào ViewController.

Nhưng làm thế nào để mỗi khi tap vào button thì gọi api và đổi trạng thái tương ứng của UISwitch?

Chúng ta hãy vào file SampleViewModel. Sau đoạn import Bond, thêm vào đoạn code:

import Alamofire

Trong class SampleViewModel, Ngay sau đoạn var isOn: Observable<Bool> thêm vào hàm callAPI như sau:

func callAPI() {
    // 1
    AF.request("https://httpbin.org/get", method: .get, encoding: URLEncoding.default).response { (response: AFDataResponse<Data?>) in
        switch response.result {
        case .success(_):
            print("Success")
            // 2
            self.isOn.value = !self.isOn.value
            break
        case .failure(let error):
            // 3
            print("Error: %@", error.localizedDescription)
            break
        }
    }
}

Đoạn code này định nghĩa action logic mà SampleViewModel phải thực hiện phải khi user tap bào button. Trong đó:

  1. Gọi 1 http request đơn giản tới https://httpbin.org/get
  2. Nếu kết quả trả về thành công, thay đổi trạng thái thuộc tính isOn.
  3. Nếu thất bại thì đơn giản là in ra nội dung lỗi

Gọi action cho ViewModel

Chúng ta đã khai báo hàm callAPI khi tap vào button. Hàm này sẽ được gọi mỗi khi user tap vào button. Để làm việc này, chúng ta quay trở lại class SampleViewController, tìm đến hàm toggleButtonClicked và thêm vào đoạn code sau:

viewModel.callAPI()

Chắc hẳn bạn đã hình dung được luồng của demo này rồi phải không? Nó đơn giản như sau:

  1. User tap vào button, gọi hàm callAPI từ SampleViewModel
  2. Sau khi hàm callAPI hoàn tất, thuộc tính isOn của SampleViewModel thay đổi
  3. Do thuộc tính isOn của SampleViewModel đã được data binding vào SampleViewController, lúc này SampleViewController sẽ nhận được sự kiện và update trạng thái tương ứng của UISwitch.

Đến đây bạn đã gần như xong bài hướng dẫn này, giờ thì bạn hãy bấm nút run để chạy project lên và xem thành quả của mình 😃.

Tổng kết

Như vậy ở bài viết trên mình đã hướng dẫn các bước cơ bản đã thiết lập viewModel và data binding với ViewController.

Các bạn có thể thấy là với ví dụ trên trên có SampleViewModel hoàn toàn độc lập khỏi SampleViewController. Nhờ đó SampleView model thể hiện logic rõ ràng hơn và dễ unit test hơn.

Ở bài sau mình sẽ giới thiệu các bạn cách unit test mô hình MVVM trên ios. Do nội dung tương đối dài nên mình sẽ chia thành 2 phần nhỏ là test logic và test view / view controller.

Nếu như các bạn có thắc mắc hay góp ý gì xin comment vào. Mình sẽ luôn lắng nghe và cải thiện cho phù hợp với nhu cầu mọi người hơn. Xin cám ơn và hẹn gặp lại các bạn trong bài viết tiếp theo nhé! Bái bai! 😄

Related Posts

Custom text input trong Eureka

Custom picker row trong Eureka

Hướng dẫn cài đặt React Native đơn giản bao chạy được tháng 01/2020

Hướng dẫn mô hình MVVM trong ios kỳ 4: Dependency Injection và Unit Test ViewController

Hiển Phạm


Mình là một lập trình viên ios. Khi rảnh rỗi mình thích chơi game, đọc sách và tìm hiểu nhiều hơn về kỹ thuật lập trình.

Your Signature

Leave a Reply


Your email address will not be published. Required fields are marked

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}