UICollectionView перезагружает данные без вызова reloadData () - PullRequest
0 голосов
/ 17 мая 2019

Я структурировал свое приложение, используя шаблон MVVM, datasource из collectionView получает данные из viewModel. В viewModel у меня есть замыкание, которое вызывается после обновления данных, оно пропускает IndexSet разделов и [IndexPath] элементов, которые collectionView должны вставить. Однако я получаю сбой каждый раз после вызова метода вставки с ошибкой:

'Неверное обновление: неверное количество разделов. Количество разделов, содержащихся в представлении коллекции после обновления (11), должно быть равно количеству разделов, содержащихся в представлении коллекции до обновления (11), плюс или минус количество вставленных или удаленных разделов (11 вставлено, 0 Исключено) ".

Я понимаю, что означает эта ошибка, однако я заметил, что это порядок, в котором методы называются

 1. viewDidLoad()

 2.  numberOfSections(in collectionView: UICollectionView) // returns 0

 3.   update?(insertedSectionsSet, insertedRows) // the closure gets called in viewModel, insertedSectionsSet has 11 elements, that's correct

 4.   numberOfSections(in collectionView: UICollectionView) // returns 11, that's correct but it should be called after next point

 5.   viewModel.update = { [weak self] sections, items in
                DispatchQueue.main.async {
                    self?.collectionView.performBatchUpdates({
                        self?.collectionView.insertSections(sections) // crash
                        self?.collectionView.insertItems(at: items)
                    }, completion: nil)
                }
            }

Как вы можете видеть из приведенного ниже кода, я добавил распечатки перед вызовом каждого метода, и вы можете четко видеть, что numberOfSections вызывается после вызова замыкания и перед его выполнением. Это не имеет никакого смысла для меня, почему это происходит. Я полагаю, что причина сбоя заключается в вызове numberOfSections перед их вставкой, поскольку после вставки ожидается 22 секции.

обновление

NumberOfSections

закрытие

NumberOfSections

Код:

class PlaylistsDataSource: NSObject, UICollectionViewDataSource {

    ...

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        print("numberofsections")
        return viewModel.numberOfSections
    }

    ...
}

class PlaylistsMasterViewController: UIViewController {

 ...
 viewDidLoad() {
   viewModel.update = { [weak self] sections, items in
            DispatchQueue.main.async {
                print("closure")
                self?.collectionView.performBatchUpdates({
                    self?.collectionView.insertSections(sections)
                    self?.collectionView.insertItems(at: items)
                }, completion: nil)
            }
        }
 }
 ...
}

class PlaylistsMasterViewModel {

private var sectionIndexes = [String]()
private var playlistsDictionary = [String: [AWPlaylist]]()
var update: ((IndexSet, [IndexPath]) -> Void)?

var numberOfSections: Int {
    return sectionIndexes.count
}

РЕДАКТИРОВАТЬ: добавлено больше кода

extension PlaylistsMasterViewModel {

func fetchPlaylists() {
    repo.getAllPlaylists(from: [.iTunes]) { [weak self] result in
        switch result {
        case .success(let playlists):
            self?.sortIncoming(playlists: playlists)
        case .failure(let error):
            print(error.localizedDescription)
        }
    }
}

private func sortIncoming(playlists: [AWPlaylist]) {

    var insertedPlaylists = [(key: String, list: AWPlaylist)]()
    var insertedIndexes = [String]()

    func insertNewSection(playlist: AWPlaylist, key: String) {
        insertedIndexes.append(key)
        playlistsDictionary.updateValue([playlist], forKey: key)
    }

    func insertNewRow(playlist: AWPlaylist, key: String) {
        guard var value = playlistsDictionary[key] else {
            print("Oh shit")
            return
        }
        value.append(playlist)
        value.sort(by: SortingPredicates.Playlist.nameAscending)
        playlistsDictionary.updateValue(value, forKey: key)
        insertedPlaylists.append((key, playlist))
    }

    for list in playlists {
        let name = list.localizedName.uppercased().trimmingCharacters(in: CharacterSet.whitespaces)
        guard let firstCharacter = name.first else { return }
        let firstLetter = String(firstCharacter)
        let key: String
        if CharacterSet.english.contains(firstLetter.unicodeScalars.first!) {
            key = firstLetter
        } else if CharacterSet.numbers.contains(firstLetter.unicodeScalars.first!) {
            key = "#"
        } else {
            key = "?"
        }
        if playlistsDictionary[key] == nil {
            insertNewSection(playlist: list, key: key)
        } else {
            insertNewRow(playlist: list, key: key)
        }
    }

    sectionIndexes.append(contentsOf: insertedIndexes)
    sectionIndexes.sort(by: { $0 < $1 })
    let insertedSections = insertedIndexes.compactMap { index -> Int? in
        guard let sectionIndex = self.sectionIndexes.firstIndex(of: index) else {
            return nil
        }
        return sectionIndex
    }
    let insertedSectionsSet = IndexSet(insertedSections)

    let insertedRows = insertedPlaylists.compactMap { tuple -> IndexPath? in
        if let section = self.sectionIndexes.firstIndex(of: tuple.key) {
            if let row = self.playlistsDictionary[tuple.key]?.firstIndex(where: { $0.equals(tuple.list) }) {
                return IndexPath(row: row, section: section)
            }
        }
        return nil
    }
    print("update")
    update?(insertedSectionsSet, insertedRows)

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...