Перезагрузите TableView, когда API завершит работу с MVVM

Я работаю над приложением на Swift 4. Я создаю свое приложение программно - без раскадровки.

У меня есть 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)
    }

}

И у меня есть 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)
                }

            }
        }
    }
}

Когда я проверяю didSet на var results: SearchResults?, я вижу, что значение устанавливается через myAPIClient.

Что я бы сделал, так это проинструктировать мою таблицу ViewController перезагрузить данные после того, как это значение будет установлено.

Я не уверен, как этого добиться? Я думал, что могу использовать didSet на cellViewModels и обратиться к методу на моем ViewController. Это не работает или я пока не понимаю, как это сделать.

Я надеюсь увидеть, что количество строк будет обновлено через viewModel.cellViewModels.count в моем SearchController.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
1 257
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете изменить свой 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()
                }

            }
        }
    }

Наконец, вы можете перезагрузить tableView

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

Люди могут часто просить вас связаться с implement protocols и установить связь между ViewModel и View. Но использовать ли блоки или протоколы - это всегда детали реализации проекта :)

Надеюсь это поможет.

Да конечно! Большое спасибо, работал как шарм

PetePete 31.07.2018 19:17

@petepete: Я рад, что смог помочь :) Удачного кодирования

Sandeep Bhandari 31.07.2018 19:18

Другие вопросы по теме