如何在刷新表视图之前获取视图模型中的存储库列表?
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。当我调用一个搜索方法时,我会在服务器响应之前重新加载表格视图。
所以应用流程应该是:
用户在搜索栏中键入搜索查询。在SearchViewController
的searchBarSearchButtonClicked(_:)
中调用了我的方法进行搜索。该方法在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() 不刷新列表视图
如何从多个控制器获取数据到 Laravel Blade 视图中?
片段中的Android ListView - 获取新数据后刷新表的问题