迅速/IOSのMVVMパターンサンプル


MVVMは、より多くのイベント指向アプリケーションがなっている間、より人気が得られているパターンです.MVVM対IOS開発の古典的なMVCを使用することに多くの利点があります.そして、完全にビジネス・ロジックをプレゼンテーション層と分け始めます.あまりにも多くのことをする責任がある「大規模なViewController」を持つ代わりに、我々はネットワークまたはローカルデータベースから他の実体にデータを要求するようなものを代表することができます.

すべてのこのアプリケーションロジックViewModelの中には、ビューが何であるか、ビューが何を知っていることはありません.何がこのアーキテクチャをかなりテスト可能にして、それを可能な限りダムとして残している見解から離れて複雑さをとります.
ビューはViewModelを所有しており、UIを更新するための変更を常に“聞く”です.ここでは、ビューの変更がある場合は、有名な“双方向データバインド”、モデルが更新され、モデルの変更がある場合は、ビューが更新され、常に中間モデルとして持っている.
さて、我々がこれを実際に見るならば、どうですか?次のシナリオを想像してください.私はGithubのAPIレストとつながっているアプリケーションを開発し、リポジトリの中から検索し、その中の1つを選択し、最新のコミットを見ることができます.始めましょう!
私は検索機能から始めるつもりです、私は簡潔さのために多くのものを無視します、しかし、あなたは最後にすべてのソースコードを見ることができます.
Viewモデルを満たすプロトコルをコード化しましょう.
protocol SearchRepositoriesDelegate {
    func searchResultsDidChanged()
}

protocol SearchViewModelType {
    var results: [SearchResult] {get}

    var query: String {get set}

    var delegate: SearchRepositoriesDelegate? {get set }
}
結果のプロパティ、結果を取得するクエリのプロパティ、および変更があったビューに通知するデリゲート.簡単、右?
別のシナリオの' SearchRepositoriesデリゲート'は、いくつかのデータバインディング機構に置き換えられたり、オブザーバブルを実装したりすることに注意してください.
次に、ViewModelは次のように動作します.
1 -ビューにはViewModelへの参照があります.
2 -ユーザーが検索バーに入力している間、ビューはクエリに基づいてViewModelの' Query 'プロパティを更新します.
3 - 'クエリ'プロパティが更新されるたびに、ViewModelはGitHub APIレストに要求を行い、結果を更新します.
4 -サーバー応答があると、ViewModelは結果に変更があったというビュー(デリゲートを通して)に通知します.
5 -関数' searchResultsdidChanged 'と呼ばれるたびに、ビューはUIを更新します.
実装方法を見てみましょう.
ViewModel :
    class SearchViewModel : SearchViewModelType {
    var delegate: SearchRepositoriesDelegate?

    var results : [SearchResult] = [] {//0 results by default
        didSet{
            delegate?.searchResultsDidChanged() //notify
        }
    }

    var searchService: SearchService

    var query: String = "" {
        didSet {
            if query == "" {
                results = []
            }else {
                performSearch()
            }
        }
    }

    init(service: SearchService) {
        self.searchService = service
    }

    private func performSearch() {
        searchService.search(query: self.query)
            .onSuccess { results in
                self.results = results
            }.onFailure { error in
                //do nothing
        }
    }
}
ビュー
class SearchViewController: UIViewController {

    ...

    var searchViewModel: SearchViewModelType!

    override func viewDidLoad() {
        super.viewDidLoad()

        searchViewModel.delegate = self

        ...
    }
}

extension SearchViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchViewModel.query = searchText
    }
}

extension SearchViewController: SearchRepositoriesDelegate {
    func searchResultsDidChanged() {
        self.tableView.reloadData()
    }
}

...
ユーザーが検索バーに入力している間は、プロパティ'クエリ'が更新され、ViewModelがサーバー側を要求します.要求が完了すると、ビューに通知し、UITableView ' reloadData ()'関数を呼び出してUIの変更を反映します.見たことがあるかもしれませんが、クラスSearchViewModelは、それが正しく動作しているかどうかをチェックするためにmock ' searchService 'オブジェクトを作成するだけでよいので、テストするのはとても簡単です.ViewModelはビューへの参照を持ちません、そして、ビューはすべてのビジネスロジックから免除されます.
以上です.this linkですべてのソースコードを見て、どんな質問についてもコメントしないでください.