Массив TableViewCells переупорядочивается после обновления TableView. - PullRequest
0 голосов
/ 05 февраля 2020

привет, друзья-программисты,

У меня возникла проблема с UITableView swift, и я просто не могу найти ошибку.

Я довольно опытный с TableViews iOS, и я знаю, как они используют очередь для максимально возможной производительности.

Обычно я просто строю массив UITableViewCells в моем ViewController и обновить TableView на основе этого массива. С помощью этой техники я могу использовать один класс DataSource для всех моих TableViews, который очень чистый и всегда работал нормально.

До сих пор: это мой первый TableView со многими ячейками одного типа, который я добавляю новые ячеек, если пользователь нажимает на последнюю ячейку, ячейку «LoadMore». Но проблема в том, что, если указанная ячейка «LoadMore» нажимается, как только обновляется TableView, TableView и даже массив tableViewCells переупорядочиваются и даже содержат двойные записи, которые не могут быть представлены правильно.

I не могу найти причину для этого. Все нормально, и все данные и массив tableViewCells однозначно верны, пока не будет вызван reViewData () TableViews. Я уже много раз проверял, что они содержат до и после обновления.

Вот (уменьшенный) код для моего ViewController, который, кстати, содержит только TableView:

import UIKit

class UserDataTableViewController: UIViewController, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    //Auto updating TableView
    var tableViewCells = [UITableViewCell]() {
        didSet {
            dataSource.update(with: tableViewCells)
            tableView.reloadData()
            tableView.beginUpdates()
            tableView.endUpdates()
        }
    }

    //DataSource for Table View
    var dataSource = NormalTableDataSource(cells: nil)

    override func viewDidLoad() {
        super.viewDidLoad()

        //TableView
        tableView.dataSource = dataSource
        tableView.delegate = self
        tableView.separatorColor = .darkText

        //get next data
        nextData()
    }

    func nextData() {
        if let data = self.data {
            //some code that finds the next data and then calls:
            addDataToTableView(data: nextData, morePages: true)
        }
    }

    func addDataToTableView(data: Array<Any>, morePages: Bool = false) {
        //create temp array out of old tableViewCells array
        var tempCells = tableViewCells

        //remove LoadMore cell if it exists
        if (tempCells.count > 0) {
            tempCells.removeLast()
        }

        //(Rating is a simple Struct)
        if let ratings = data as? [Rating] {
            //This loop runs aprox. 25 times
            for rating in ratings {
                let cell = tableView.dequeueReusableCell(withIdentifier: "UserRatedAlbumCell") as! UserRatedAlbumCell
                cell.update(rating: rating)
                tempCells.append(cell)
            }
        }

        //add LoadMore cell
        if (morePages) {
            let loadMoreCell = tableView.dequeueReusableCell(withIdentifier: "LoadMoreCell")!
            tempCells.append(loadMoreCell)
        }

        //update array, which automatically updates the tableView
        self.tableViewCells = tempCells
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return tableViewCells[indexPath.row].frame.size.height
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableViewCells[indexPath.row]

        if (cell.reuseIdentifier == "LoadMoreCell") {
            self.nextData()
        }

        tableView.deselectRow(at: indexPath, animated: true)
    }
}

И вот (также немного уменьшенный) код внутри класса «UserRatedAlbumCell»:

import UIKit

class UserRatedAlbumCell: UITableViewCell {

    @IBOutlet weak var albumCoverImage: UIImageView!
    @IBOutlet weak var albumNameLabel: UILabel!

    //data
    var album: Album?
    var rating: Rating?

    func update(rating: Rating) {
        self.rating = rating
        albumNameLabel.text = ""
        albumCoverImage.image = nil

        //---Some async task with completion block that returns "album":
        {
            if let album = album {
                DispatchQueue.main.async {
                    self.update(album: album, rating: rating)
                }
            }
        }
        //---
    }

    func update(album: Album) {
        self.album = album

        albumNameLabel.text = album.attributes?.name

        if let url = album.attributes?.artwork.url(forWidth: 150) {
            albumCoverImage.downloaded(with: url)
        }
    }
}

А вот мой «NormalTableDataSource», который, как было сказано ранее, используется почти во всех моих TableViews:

import UIKit

class NormalTableDataSource: NSObject, UITableViewDataSource {

    private var cells: [UITableViewCell]?

    init(cells: [UITableViewCell]?) {
        self.cells = cells
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cells?.count ?? 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if let cells = cells {
            return cells[indexPath.row]
        } else {
            return UITableViewCell()
        }
    }

    func update(with cells: [UITableViewCell]?) {
        self.cells = cells
    }
}

Кто-нибудь знает, почему это может быть? По запросу я могу предоставить скриншоты того, что происходит с TableView. Но я могу вам сказать, что, как только LoadMore будет нажата в первый раз, все ячейки переупорядочиваются, и появляется много пустых ячеек, вероятно, вызванных двойными записями в массиве tableViewCells.

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 05 февраля 2020

Короче говоря, dequeueReusableCell предназначен для вызова из «tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath)», поэтому у вас возникают проблемы.

Более сложная история заключается в том, что она возвращает ячейки то, что само табличное представление считает больше не используемым, тот факт, что вы где-то храните ссылки на эти ячейки (например, свойство tableViewCells), ничего не меняет, табличное представление по-прежнему имеет полное право повторно использовать эти ячейки всякий раз, когда это имеет смысл , Поэтому каждый раз, когда вы вызываете nextData (), вы получаете дублированные ячейки.

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