Как получить список репозиториев в модели представления перед обновлением представления таблицы? - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь создать приложение, которое ищет GitHub-репозитории. И я использую MVVM и Мойю. Когда я вызываю метод для поиска, я перезагружаю табличное представление прежде, чем сервер отвечает.

Итак, поток приложения должен быть: Пользователь вводит поисковый запрос в строку поиска. В searchBarSearchButtonClicked(_:) из SearchViewController вызван мой метод поиска. Метод внутри 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
}

NetworkService:

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 Ответ

0 голосов
/ 24 января 2019

Ваша проблема в основном в том, что вы не обрабатываете асинхронные запросы должным образом.

Рассмотрим код:

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. 
}

Как вы можете видеть в комментариях, что произойдет здесь:

  • звонок в сеть
  • печать (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 будет вызвано сразу после запуска сетевого вызова, и сетевой запрос не успел бы вернуть данные.

Пара полезных ресурсов по теме:

...