Обновите представление таблицы на основе набора данных с сервера и локального

#swift #uitableview

Вопрос:

У меня есть просмотр таблиц, в котором отображаются все новости, затем, если какие-либо новости обновляются или добавляются новые новости, я проверяю и обновляю их следующим образом. Мне интересно, правильный ли мой подход, а также ищу лучшие варианты(tableviewdiffsource?)

В настоящее время пользователь видит следующие 4 новости в таком порядке

[n1, n2, n3, n4]

когда пользователь нажимает на обновление, он получает 3 новости с сервера : [n4, n5, n6]

теперь я должен отображать новости в таком порядке [n4, n5, n6, n1, n2, n3]

 var allNews = [News]()
func didFetchNews(newNews:[News]) {
    var news:[News] = newNews
    var newsSet = Set(newNews)

    var deletedPaths = [IndexPath]()

    for i in 0..<allNews.count {
       let news = allNews[i];
       if !newsSet.contains(news) {
         news.append(news)
       } else {
         deletedPaths.append(IndexPath(row: i, section: 0))
       }
    }

    var insertedPath = [IndexPath]()
    for i in 0..<newNews.count {
        insertedPath.append(IndexPath(row: i, section: 0))
    }

    self.tableView.beginUpdates()
    self.tableView.insertRows(at: insertedPath, with: .automatic)
    self.tableView.deleteRows(at: deletedPaths, with: .automatic)
    self.tableView.endUpdates()
}
 

Ответ №1:

DiffableDataSource вероятно, это самое эффективное решение.

Однако ваш код также может быть оптимизирован с помощью функций более высокого уровня, таких как filter и map .

Сначала рассчитываются индексы обновленных новостей. Поскольку новые элементы вставляются сверху, пути индекса вставки равны индексам новых элементов.

Затем элементы удаляются по отфильтрованным индексам, а новые элементы вставляются по индексу 0. reversed() Позволяет избежать сбоя вне диапазона.

 func didFetchNews(newNews: [News]) {
    let deletionIndices = allNews.indices.filter{newNews.contains(allNews[$0])}
    let deletionIndexPaths = deletionIndices.map{IndexPath(row: $0, section: 0)}
    let insertionIndexPaths = newNews.indices.map{IndexPath(row: $0, section: 0)}
    
    for index in deletionIndices.reversed() { allNews.remove(at: index) }
    allNews.insert(contentsOf: newNews, at: 0)

    self.tableView.beginUpdates()
    self.tableView.insertRows(at: insertionIndexPaths, with: .automatic)
    self.tableView.deleteRows(at: deletionIndexPaths, with: .automatic)
    self.tableView.endUpdates()
} 
 

Комментарии:

1. Большое вам спасибо за этот прекрасный код. Мне интересно , почему мы и тогда, а не сначала и потом . insertRows deleteRows deleteRows insertRows self.table.insertRows(at: IndexPaths) Значит , имеется в виду self.table.deleteRows(at: IndexPaths) .

2. Путем обертывания insert/delete/move операторов в begin-/endUpdates рамки достаточно умен, чтобы выполнять изменения в правильном порядке.

3. порядок insertRows и deleteRows в том begin endUpdates не имеет значения, тогда верно?

4. Да, порядок внутри блока не имеет значения.

5. Большое спасибо @vadian