简体   繁体   English

使用MVVM完成API后重新加载TableView

[英]Reload TableView when API completes w/ MVVM

I am working on an app in Swift 4. I am building my app programmatically - no storyboards. 我正在使用Swift 4开发一个应用程序。我正在以编程方式构建我的应用程序 -没有情节提要。

I have a ViewController that looks like this 我有一个看起来像这样的ViewController

class SearchController: UITableViewController {

    private let cellID = "cellID"

    fileprivate let searchController = UISearchController(searchResultsController: nil)
    fileprivate let viewModel = SearchViewModel(client: DiscogClient())

    override func viewDidLoad() {
        super.viewDidLoad()

        setupSearchBar()
        setupTableView()
    }

    fileprivate func setupSearchBar() -> Void {
        navigationItem.hidesSearchBarWhenScrolling = false
        navigationItem.searchController = searchController

        searchController.searchBar.delegate = self

    }

    fileprivate func setupTableView() -> Void {
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
        tableView.tableFooterView = UIView()
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.cellViewModels.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
        return cell
    }

}

extension SearchController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        viewModel.search(term: searchText)
    }

}

And I have a ViewModel that looks like this 我有一个看起来像这样的ViewModel

import Foundation
import UIKit

class SearchViewModel {
    var cellViewModels: [Result] = []

    private let client: APIClient
    var results: SearchResults? {
        didSet {
            for result in (results?.results)! {
                cellViewModels.append(result)
            }
        }
    }

    var isLoading: Bool = false {
        didSet {
            showLoading?()
        }
    }

    var showLoading: (() -> Void)?
    var reloadData: (() -> Void)?
    var showError: ((Error) -> Void)?

    init(client: APIClient) {
        self.client = client
    }

    func search(term: String) {

        if let client = client as? DiscogClient {
            let endpoint = DiscogsEndpoint.search(term: term, searchType: .release)
            client.fetch(with: endpoint) { (either) in

                switch either {
                case .success(let results):
                    self.results = results
                case .error(let error):
                    self.showError?(error)
                }

            }
        }
    }
}

When I check didSet on var results: SearchResults? 当我在var results: SearchResults?上检查didSetvar results: SearchResults? I can see that the value is being set via my APIClient . 我可以看到该值是通过我的APIClient设置的。

What I would to do is instruct my ViewController table to reload it's data once that value is set. 我要做的就是指示ViewController表在设置该值后重新加载其数据。

I am unsure how to achieve this though? 我不确定如何实现这一目标? I thought I could use a didSet on cellViewModels and reach out to a method on my ViewController. 我以为我可以在didSet上使用didSet并扩展到ViewController上的方法。 This does not work or I do not understand how to do this yet. 这行不通,或者我不知道如何执行此操作。

I am hoping to see for now, the number of rows be updated via viewModel.cellViewModels.count within my SearchController 我希望现在看到行数通过SearchController中的viewModel.cellViewModels.count更新

You can modify your search to accept completion block 您可以修改search以接受完成阻止

func search(term: String, @escaping completion :() -> ()) {

        if let client = client as? DiscogClient {
            let endpoint = DiscogsEndpoint.search(term: term, searchType: .release)
            client.fetch(with: endpoint) { (either) in

                switch either {
                case .success(let results):
                    self.results = results
                    completion()
                case .error(let error):
                    self.showError?(error)
                    completion()
                }

            }
        }
    }

Finally you can reload tableView 最后,您可以重新加载tableView

    self.search(term: "abcd") {
        self.tableView.reloadData()
    }

People might often ask you to implement protocols and establish communication between ViewModel and View. 人们可能经常会要求您implement protocols并在ViewModel和View之间建立通信。 But whether to use blocks or protocols is always a design implementation details :) 但是,使用块还是协议始终是设计实现的详细信息:)

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM