From 3fdf8b3728b62c41f4357fd690e0c716bf5fe34e Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 26 Sep 2018 21:33:55 -0700 Subject: [PATCH] Improve scrolling performance with very large timelines. Reload visible cells only, and minimize the amount of looping through articles in the array. --- .../MainWindow/Timeline/ArticleArray.swift | 30 -------------- .../Timeline/TimelineViewController.swift | 39 +++++++++++++------ 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/NetNewsWire/MainWindow/Timeline/ArticleArray.swift b/NetNewsWire/MainWindow/Timeline/ArticleArray.swift index b9b7b4076..575e70d0b 100644 --- a/NetNewsWire/MainWindow/Timeline/ArticleArray.swift +++ b/NetNewsWire/MainWindow/Timeline/ArticleArray.swift @@ -50,20 +50,6 @@ extension Array where Element == Article { }) } - func indexesForArticleIDs(_ articleIDs: Set) -> IndexSet { - - var indexes = IndexSet() - - articleIDs.forEach { (articleID) in - let oneIndex = rowForArticleID(articleID) - if oneIndex != NSNotFound { - indexes.insert(oneIndex) - } - } - - return indexes - } - func sortedByDate(_ sortDirection: ComparisonResult) -> ArticleArray { let articles = sorted { (article1, article2) -> Bool in @@ -118,19 +104,3 @@ extension Array where Element == Article { } } -private extension Array where Element == Article { - - func rowForArticleID(_ articleID: String) -> Int { - - if let index = index(where: { $0.articleID == articleID }) { - return index - } - - return NSNotFound - } - - func rowForArticle(_ article: Article) -> Int { - - return rowForArticleID(article.articleID) - } -} diff --git a/NetNewsWire/MainWindow/Timeline/TimelineViewController.swift b/NetNewsWire/MainWindow/Timeline/TimelineViewController.swift index a46e97e44..bdd06e929 100644 --- a/NetNewsWire/MainWindow/Timeline/TimelineViewController.swift +++ b/NetNewsWire/MainWindow/Timeline/TimelineViewController.swift @@ -361,7 +361,7 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { guard let articles = note.userInfo?[Account.UserInfoKey.articles] as? Set
else { return } - reloadCellsForArticleIDs(articles.articleIDs()) + reloadVisibleCells(for: articles) } @objc func feedIconDidBecomeAvailable(_ note: Notification) { @@ -369,10 +369,15 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed else { return } - let articlesToReload = articles.filter { (article) -> Bool in + let indexesToReload = tableView.indexesOfAvailableRowsPassingTest { (row) -> Bool in + guard let article = articles.articleAtRow(row) else { + return false + } return feed == article.feed } - reloadCellsForArticles(articlesToReload) + if let indexesToReload = indexesToReload { + reloadCells(for: indexesToReload) + } } @objc func avatarDidBecomeAvailable(_ note: Notification) { @@ -432,22 +437,32 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { return nil } - private func reloadCellsForArticles(_ articles: [Article]) { - - reloadCellsForArticleIDs(Set(articles.articleIDs())) + private func reloadVisibleCells(for articles: [Article]) { + reloadVisibleCells(for: Set(articles.articleIDs())) + } + + private func reloadVisibleCells(for articles: Set
) { + reloadVisibleCells(for: articles.articleIDs()) } - private func reloadCellsForArticleIDs(_ articleIDs: Set) { - + private func reloadVisibleCells(for articleIDs: Set) { if articleIDs.isEmpty { return } - let indexes = articles.indexesForArticleIDs(articleIDs) - reloadCells(for: indexes) + let indexes = indexesForArticleIDs(articleIDs) + reloadVisibleCells(for: indexes) + } + + private func reloadVisibleCells(for indexes: IndexSet) { + let indexesToReload = tableView.indexesOfAvailableRowsPassingTest { (row) -> Bool in + return indexes.contains(row) + } + if let indexesToReload = indexesToReload { + reloadCells(for: indexesToReload) + } } private func reloadCells(for indexes: IndexSet) { - if indexes.isEmpty { return } @@ -776,7 +791,7 @@ private extension TimelineViewController { func selectArticles(_ articleIDs: [String]) { - let indexesToSelect = articles.indexesForArticleIDs(Set(articleIDs)) + let indexesToSelect = indexesForArticleIDs(Set(articleIDs)) if indexesToSelect.isEmpty { tableView.deselectAll(self) return