Clean Architecture và MVVM trên iOS (Swift) phần 2

Tram Ho

phần 1 chúng ta đã tìm hiểu về Clean Architecture. Trong phần 2 này, chúng ta sẽ tiếp tục với mô hình MVVM trong series Clean Architecture và MVVM trên iOS (Swift)

MVVM

Model-View-ViewModel pattern (MVVM) phân tách rõ ràng giữa UI và domain. Khi sử dụng chúng (MVVM) với Clean Architecture có thể phân tách rõ ràng giữa các layer UI và Presentation.

Việc triển khai các View khác nhau có thể sử dụng chung ViewModel. Ví dụ: bạn có thể triển khai CarsAroundListViewCarsAroundMapView và sử dụng CarsAroundViewModel cho cả hai. Bạn cũng có thể triển khai một View UIkit và View khác với SwifUI. Điều quan trọng cần nhớ là không import UIkit, WatchKit, SwiftUI bên trong ViewModel của bạn, điều này giúp bạn có thể tái sử dụng nó trong các platform khác nếu cần.

° ° °

image.png

Ví dụ, liên kết dữ liệu giữa ViewViewModel có thể được thực hiện với các closures, Delegate hoặc Observerble (ví dụ: RxSwift). CombineSwiftUI cũng có thể được sử dụng nhưng chỉ khi hệ thống iOS >= 13. View có mối quan hệ trực tiếp với ViewModel và thông báo cho nó bất cứ khi nào một event bên trong View xảy ra. Từ ViewModel, không có tham chiếu trực tiếp đến View (chỉ Data Binding).

Trong ví dụ này, chúng tôi sẽ sử dụng kết hợp đơn giản giữa Closure và didSet để tránh sự phụ thuộc của bên thứ ba:

Lưu ý: Đây là phiên bản Observable rất đơn giản, để xem toàn bộ triển khai với multiple observerbleobserver removal : Observerble.

Một ví dụ về Data Binding của ViewController:

Note: Không được phép truy cập viewModel từ observing closure. Nó là nguyên nhân của retain cycle(memory leak). Bạn có thể truy cập viewModel chỉ bằng self: self?.viewModel.

Một ví dụ data binding trên TableViewCell (Reusable Cell):

Note: Chúng ta phải hủy liên kết nếu View có thể reusable (ví dụ: UITableViewCell)

MVVM Templates có thể xem ở đây

MVVMs Communication

Delegation

ViewModel của một MVVM (screen) giao tiếp with ViewModel khác của MVVM(screen) khác sử dụng delegation pattern:

image.png

Ví dụ, chúng ta có ItemsListViewModelItemEditViewModel. Sau đó tạo một protocol ItemEditViewModelDelegate với phương thức ItemEditViewModelDidEditItem(item). Và cho viewmodel conform với protocol này: extension ListItemsViewModel: ItemEditViewModelDelegate

Note: Chúng ta cũng có thể đặt tên Delegates trong trường hợp này như là một Responders: ItemEditViewModelResponder

Closures

Một cách khác để giao tiếp là sử dụng closures được chỉ định hoặc đưa vào bởi FlowCoordinator. Trong example project chúng ta có thể thấy cách mà MoviesListViewModel sử dụng action closure showMovieQueriesSuggestions để show MoviesQueriesSuggestionsView. Nó cũng truyền parameter (_ didSelect: MovieQuery) -> Void nên chúng cũng có thể được gọi từ View đó. cách giao tiếp này được kết nối bên trong MoviesSearchFlowCoordinator, xem ví dụ bên dưới:

Tách layer thành frameworks (Modules)

Bây giờ, với mỗi layer (Domain, Presentation, UI, Data, Infrastructure Network) của example app có thể dễ dàng tách thành frameworks riêng biệt.

Sau đó bạn có thể sử dụng các frameworks đó vào project bằng cách sử dụng CocoaPods. Bạn có thể thấy example project ở đây:

Note: Bạn cần phải delete ExampleMVVM.xcworkspace và run pod install để tạo ra một cái mới, bởi vì đó là một issue cấp phép.

° ° °

image.png

° ° °

Dependency Injection Container

Dependency injection là một kỹ thuật theo đó một đối tượng cung cấp các phụ thuộc của một đối tượng khác. DIContainer trong ứng dụng của bạn là đơn vị trung tâm của tất cả các lần injection.

Using dependencies factory protocols

Một trong những option để khai báo một dependencies protocol là delegates, sự khởi tạo của dependency cho DIContainer. Để làm điều này, chúng ta cần define MoviesSearchFlowCoordinatorDependencies protocol và cho MoviesSceneDIContainer confirm chính protocol này, và sau đó, đưa vào bên trong MoviesSearchFlowCoordinator như một param để khởi tạo và present MoviesListViewController.
Dưới đây là các bước :

Using closures

Một option khác là closures. Để làm điều này chúng ta cần khai báo closure bên trong class cần injection và sau đó chúng ta inject closure này.
Ví dụ:

Source code

 

Resources

Advanced iOS App Architecture

The Clean Architecture

The Clean Code

Kết luận

Architectural patterns được sử dụng hầu hết trong mobile are Clean Architecture(Layered), MVVM, and Redux.

MVVM và Clean Architecture tất nhiên có thể sử dụng riêng biệt, nhưng MVVM chỉ tách biêt bên trong của Presentation Layer, trong khi Clean Architecture tách code của bạn thành các modular layer điều đó có thể làm có project có thể dễ dàng test, tái sử dụng.

IĐiều quan trọng là không được bỏ qua việc tạo Use Case, mặc dù Use Case không làm điều gì khác ngoài calling Repository. Bằng cách này, kiến trúc của bạn sẽ dễ hiểu khi một dev mới nhìn thấy các Use Case của ban.

Mặc dù điều này sẽ hữu ích như một điểm khởi đầu, nhưng không có sản phẩm, phương pháp hay thủ thuật nào có thể đảm bảo đó là kết quả tốt nhất . Tùy vào nhu cầu của dự án mà bạn có thể chọn một kiến trúc phù hợp.

Clean Architecture work thực sự tốt với (Test Driven Development) TDD. Architecture này làm cho project của bạn mang tính testable và các layer có thể thay thế dễ dàng (UI and Data).

END

link gốc bài viết : https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3

 

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo