如何在刷新表视图之前获取视图模型中的存储库列表?

Posted

技术标签:

【中文标题】如何在刷新表视图之前获取视图模型中的存储库列表?【英文标题】:How can I get a list of repositories in the view model before the table view is refreshed? 【发布时间】:2019-01-24 10:04:06 【问题描述】:

我正在尝试构建一个搜索 GitHub 存储库的应用程序。我正在使用 MVVM 和 Moya。当我调用一个搜索方法时,我会在服务器响应之前重新加载表格视图。

所以应用流程应该是: 用户在搜索栏中键入搜索查询。在SearchViewControllersearchBarSearchButtonClicked(_:) 中调用了我的方法进行搜索。该方法在SearchViewModel 内部。所以视图模型的方法触发RepositoryService然后NetworkService

我放了一些打印语句来查看执行顺序。在控制台中,我得到了:2 3 4 (Here the table view is refreshing) 1。我尝试在不同的地方使用 GCD,也尝试使用障碍。归根结底,在调用print(1) 之前,表格视图仍在刷新。

SearchViewController:

extension SearchViewController: UISearchBarDelegate 
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) 
        guard let query = searchBar.text, query.count > 2 else  return 
        viewModel.searchRepositories(withQuery: query)  [weak self] in
            guard let self = self else  return 
            print(4)
            print("Reloading...")
            self.tableView.reloadData()
        
    

SearchViewModel:

var repositories = [Repository]()

func searchRepositories(withQuery query: String, completion: @escaping () -> Void) 
    repositories = repositoryService.searchRepositories(withQuery: query)
    print(3)
    completion()

RepositoryService:

private var repositories = [Repository]()

func searchRepositories(withQuery query: String) -> [Repository] 
    networkService?.searchRepositories(withQuery: query)  [weak self] repositories in
        guard let self = self, let repositories = repositories else  return 
        self.repositories += repositories
    
    print(2)
    return self.repositories

网络服务:

func searchRepositories(withQuery query: String,
                        completionHandler: @escaping (([Repository]?) -> Void)) 
    provider?.request(.searchRepo(query: query))  result in
        switch result 
        case .success(let response):
            do 
                let repositories = try response.map(SearchResults<Repository>.self)
                print(1)
                completionHandler(repositories.items)
             catch let error 
                print(error.localizedDescription)
            

        case .failure(let error):
            print(error)
        
    

【问题讨论】:

【参考方案1】:

您的问题基本上是您没有正确处理异步请求。

考虑代码:

var repositories = [Repository]()

func searchRepositories(withQuery query: String, completion: @escaping () -> Void) 
    repositories = repositoryService.searchRepositories(withQuery: query) // here we are going to create a network request in the background, which takes time. 
    print(3)
    completion() // when you call this, your network request is still trying, so when your tableView refreshes... the data hasn't returned yet. 

正如你在 cmets 中看到的,这里会发生什么:

调用网络 打印(3) 完成 -> 重新加载表格视图 带有数据的网络响应 -> 你什么都不做。

你应该做什么......

func searchRepositories(withQuery query: String, completion: @escaping (SomeResponseType?, Error?) -> Void) 
    repositories = repositoryService.searchRepositories(withQuery: query)  response in 
         completion(results, error)
    

您已在其他地方遵循此模式,但您需要涵盖所有异步请求。

这里也一样:

func searchRepositories(withQuery query: String) -> [Repository] 
    networkService?.searchRepositories(withQuery: query)  [weak self] repositories in
        guard let self = self, let repositories = repositories else  return 
        self.repositories += repositories
    
    print(2)
    return self.repositories

return self.repositories将在网络调用开始后立即被调用,网络请求将没有时间返回数据。

关于该主题的一些有用资源:

Grand central dispatch in Swift 4 - RW URLSession tutorial - RW

【讨论】:

以上是关于如何在刷新表视图之前获取视图模型中的存储库列表?的主要内容,如果未能解决你的问题,请参考以下文章

片段中的 notifyDataSetChanged() 不刷新列表视图

ObservableCollection刷新视图MVVM

如何从多个控制器获取数据到 Laravel Blade 视图中?

片段中的Android ListView - 获取新数据后刷新表的问题

在 Spring Data Repository 中刷新 Oracle Materialized 视图

如何通过单击另一个列表视图 WPF 中的元素来刷新列表视图