J'essaie d'implémenter la vue tableau avec la nouvelle API DiffableDataSource, mais les cellules ne se chargent tout simplement pas :

var tableView = UITableView()
    var currencyPairsArray = [String]()
    lazy var fetcher = NetworkDataFetcher()

    lazy var searchText = String()
    lazy var searchArray = [String]()
    lazy var searchController: UISearchController = {
        let controller = UISearchController(searchResultsController: nil)
        controller.hidesNavigationBarDuringPresentation = false
        controller.obscuresBackgroundDuringPresentation = false
        controller.searchBar.delegate = self
        return controller
    }()

    fileprivate var dataSource : UITableViewDiffableDataSource<Section, String>!

    var searchBarIsEmpty: Bool {
        return searchController.searchBar.text?.isEmpty ?? true
    }

    override func viewDidLoad() {
        super.viewDidLoad()


        setupVC()
        setupTableView()
        setupDataSource()
        performSearch(with: nil)


        fetcher.fetchCurrencyPairs { [weak self] pairsArray in
            self?.currencyPairsArray.append(contentsOf: pairsArray)
            DispatchQueue.main.async {
                self?.tableView.reloadData()
            }
        }
        //tableView.reloadData()

        // Do any additional setup after loading the view.
    }

    func setupVC() {
        view.backgroundColor = .white
        view.addSubview(tableView)
        navigationItem.title = "Currency pairs"
        navigationItem.searchController = searchController
        navigationItem.hidesSearchBarWhenScrolling = false

    }

    func setupTableView() {
        tableView.delegate = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.pinToSuperView()
        tableView.register(UINib(nibName: "CurrencyPairCell", bundle: nil), forCellReuseIdentifier: CurrencyPairCell.reuseIdentifier)
    }


    func setupDataSource() {
        dataSource = UITableViewDiffableDataSource<Section, String>(tableView: tableView, cellProvider: { [weak self] (tableView, indexPath, _) ->  UITableViewCell?  in
            let cell = tableView.dequeueReusableCell(withIdentifier: CurrencyPairCell.reuseIdentifier, for: indexPath) as! CurrencyPairCell
            cell.delegate = self
            let pair = self?.currencyPairsArray[indexPath.row].formattedPair()
            cell.currencyPairLabel.text = pair
            cell.currencyPair = self?.currencyPairsArray[indexPath.row] ?? ""
            return cell
        })
    }

    func performSearch(with filter: String?) {

        var snapshot = NSDiffableDataSourceSnapshot<Section, String>()

        if let filter = filter {
            let filteredPairs = currencyPairsArray.filter {$0.contains(filter)}

            snapshot.appendSections([.main])
            snapshot.appendItems(filteredPairs, toSection: .main)
            dataSource.apply(snapshot, animatingDifferences: true)
        } else {
            let pairs = currencyPairsArray.sorted()
            snapshot.appendSections([.main])
            snapshot.appendItems(pairs, toSection: .main)
            dataSource.apply(snapshot)
        }

    }

}

extension CurrencyListViewController: UISearchBarDelegate {

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

        performSearch(with: searchText)
    }

}

extension CurrencyListViewController {
    fileprivate enum Section: Hashable {
        case main
    }
}

Aussi, je reçois un avertissement du xcode:

[TableView] Avertissement une seule fois : UITableView a reçu l'ordre de mettre en page ses cellules visibles et autres contenus sans être dans la hiérarchie de la vue (la vue du tableau ou l'une de ses supervues n'a pas été ajoutée à une fenêtre). Cela peut provoquer des bogues en forçant les vues à l'intérieur de la vue de la table à charger et à effectuer la mise en page sans informations précises (par exemple, les limites de la vue de la table, la collection de traits, les marges de mise en page, les encarts de zone de sécurité, etc.), et entraînera également une surcharge de performances inutile en raison de passes de mise en page supplémentaires . Créez un point d'arrêt symbolique à UITableViewAlertForLayoutOutsideViewHierarchy pour détecter cela dans le débogueur et voir ce qui a causé cela, afin que vous puissiez éviter complètement cette action si possible, ou la reporter jusqu'à ce que la vue tabulaire ait été ajoutée à une fenêtre. Vue de tableau: ; couche = ; contentOffset : {0, 0} ; contentSize : {414, 0} ; ajustéContentInset : {0, 0, 0, 0} ; dataSource : <TtGC5UIKit29UITableViewDiffableDataSourceOC11FXTMproject26CurrencyListViewControllerP10$107a9eb7c7SectionSS : 0x600002960ca0>>

2
Ruslan 22 févr. 2020 à 12:24

1 réponse

Meilleure réponse

Tout d'abord, il y a une grosse erreur de conception dans votre code.

Avec UITableViewDiffableDataSource, arrêtez de penser aux chemins d'index et aux tableaux de sources de données. Pensez plutôt aux éléments de la source de données.

Dans setupDataSource, vous obtenez toujours l'élément de modèle de la ligne à partir du tableau de source de données currencyPairsArray, que vous alliez ou non afficher les données filtrées. Oubliez currencyPairsArray et le chemin d'index. Profitez du troisième paramètre de la fermeture qui représente l'élément.

func setupDataSource() {
    dataSource = UITableViewDiffableDataSource<Section, String>(tableView: tableView, cellProvider: { [weak self] (tableView, _, pair) ->  UITableViewCell?  in
        let cell = tableView.dequeueReusableCell(withIdentifier: CurrencyPairCell.reuseIdentifier, for: indexPath) as! CurrencyPairCell
        cell.delegate = self
        cell.currencyPairLabel.text = pair.formattedPair()
        cell.currencyPair = pair
        return cell
    })
}

Pour supprimer l'avertissement, effectuez le premier rechargement des données sans animation. Ajoutez un paramètre booléen à performSearch. Et plutôt que de vérifier nil, vérifiez la chaîne vide

func performSearch(with filter: String, animatingDifferences: Bool = true) {

    var snapshot = NSDiffableDataSourceSnapshot<Section, String>()

    let pairs : [String]
    if filter.isEmpty {
        pairs = currencyPairsArray.sorted()
    } else {
        pairs = currencyPairsArray.filter {$0.contains(filter)}           
    }
    snapshot.appendSections([.main])
    snapshot.appendItems(pairs, toSection: .main)
    dataSource.apply(snapshot, animatingDifferences: animatingDifferences)

}

Et n'appelez jamais tableView.reloadData() lorsque vous utilisez UITableViewDiffableDataSource, ce qui est probablement la raison de votre problème.

Remplacer

    performSearch(with: nil)


    fetcher.fetchCurrencyPairs { [weak self] pairsArray in
        self?.currencyPairsArray.append(contentsOf: pairsArray)
        DispatchQueue.main.async {
            self?.tableView.reloadData()
        }
    }

Avec

    fetcher.fetchCurrencyPairs { [weak self] pairsArray in
        self?.currencyPairsArray.append(contentsOf: pairsArray)
        DispatchQueue.main.async {
            self?.performSearch(with: "", animatingDifferences: false)
        }
    }
1
vadian 22 févr. 2020 à 10:27