Fix potential race condition with DiffableTimelineLikeTableViewController
This commit is contained in:
parent
f109253bba
commit
c0097ba752
|
@ -168,7 +168,7 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadOlderItems(currentSnapshot: Snapshot, completion: @escaping (LoadResult) -> Void) {
|
override func loadOlderItems(currentSnapshot: @escaping () -> Snapshot, completion: @escaping (LoadResult) -> Void) {
|
||||||
guard let older = older else {
|
guard let older = older else {
|
||||||
completion(.failure(.noOlder))
|
completion(.failure(.noOlder))
|
||||||
return
|
return
|
||||||
|
@ -176,12 +176,12 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
|
|
||||||
if #available(iOS 15.0, *),
|
if #available(iOS 15.0, *),
|
||||||
Preferences.shared.disableInfiniteScrolling && !didConfirmLoadMore {
|
Preferences.shared.disableInfiniteScrolling && !didConfirmLoadMore {
|
||||||
guard !currentSnapshot.itemIdentifiers(inSection: .footer).contains(.confirmLoadMore) else {
|
var snapshot = currentSnapshot()
|
||||||
|
guard !snapshot.itemIdentifiers(inSection: .footer).contains(.confirmLoadMore) else {
|
||||||
// todo: need something more accurate than "success"/"failure"
|
// todo: need something more accurate than "success"/"failure"
|
||||||
completion(.success(currentSnapshot))
|
completion(.success(snapshot))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var snapshot = currentSnapshot
|
|
||||||
snapshot.appendItems([.confirmLoadMore], toSection: .footer)
|
snapshot.appendItems([.confirmLoadMore], toSection: .footer)
|
||||||
self.dataSource.apply(snapshot)
|
self.dataSource.apply(snapshot)
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
|
@ -199,7 +199,7 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
var snapshot = currentSnapshot
|
var snapshot = currentSnapshot()
|
||||||
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown) }, toSection: .statuses)
|
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown) }, toSection: .statuses)
|
||||||
snapshot.deleteItems([.confirmLoadMore])
|
snapshot.deleteItems([.confirmLoadMore])
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
|
@ -208,7 +208,7 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadNewerItems(currentSnapshot: Snapshot, completion: @escaping (LoadResult) -> Void) {
|
override func loadNewerItems(currentSnapshot: @escaping () -> Snapshot, completion: @escaping (LoadResult) -> Void) {
|
||||||
guard let newer = newer else {
|
guard let newer = newer else {
|
||||||
completion(.failure(.noNewer))
|
completion(.failure(.noNewer))
|
||||||
return
|
return
|
||||||
|
@ -228,7 +228,7 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
var snapshot = currentSnapshot
|
var snapshot = currentSnapshot()
|
||||||
let newIdentifiers = statuses.map { Item.status(id: $0.id, state: .unknown) }
|
let newIdentifiers = statuses.map { Item.status(id: $0.id, state: .unknown) }
|
||||||
if let first = snapshot.itemIdentifiers(inSection: .statuses).first {
|
if let first = snapshot.itemIdentifiers(inSection: .statuses).first {
|
||||||
snapshot.insertItems(newIdentifiers, beforeItem: first)
|
snapshot.insertItems(newIdentifiers, beforeItem: first)
|
||||||
|
|
|
@ -146,7 +146,7 @@ class DiffableTimelineLikeTableViewController<Section: Hashable & CaseIterable,
|
||||||
|
|
||||||
state = .loadingOlder
|
state = .loadingOlder
|
||||||
|
|
||||||
loadOlderItems(currentSnapshot: dataSource.snapshot()) { result in
|
loadOlderItems(currentSnapshot: dataSource.snapshot) { result in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.state = .loaded
|
self.state = .loaded
|
||||||
|
|
||||||
|
@ -212,18 +212,22 @@ class DiffableTimelineLikeTableViewController<Section: Hashable & CaseIterable,
|
||||||
|
|
||||||
state = .loadingNewer
|
state = .loadingNewer
|
||||||
|
|
||||||
let snapshot = dataSource.snapshot()
|
var firstItem: Item? = nil
|
||||||
|
let currentSnapshot: () -> Snapshot = {
|
||||||
|
let snapshot = self.dataSource.snapshot()
|
||||||
|
|
||||||
var item: Item? = nil
|
for section in self.timelineContentSections() {
|
||||||
for section in timelineContentSections() {
|
|
||||||
if snapshot.indexOfSection(section) != nil,
|
if snapshot.indexOfSection(section) != nil,
|
||||||
let first = snapshot.itemIdentifiers(inSection: section).first {
|
let first = snapshot.itemIdentifiers(inSection: section).first {
|
||||||
item = first
|
firstItem = first
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadNewerItems(currentSnapshot: snapshot) { result in
|
return snapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
loadNewerItems(currentSnapshot: currentSnapshot) { result in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.refreshControl?.endRefreshing()
|
self.refreshControl?.endRefreshing()
|
||||||
self.state = .loaded
|
self.state = .loaded
|
||||||
|
@ -231,8 +235,8 @@ class DiffableTimelineLikeTableViewController<Section: Hashable & CaseIterable,
|
||||||
switch result {
|
switch result {
|
||||||
case let .success(snapshot):
|
case let .success(snapshot):
|
||||||
self.dataSource.apply(snapshot, animatingDifferences: false)
|
self.dataSource.apply(snapshot, animatingDifferences: false)
|
||||||
if let item = item,
|
if let firstItem = firstItem,
|
||||||
let indexPath = self.dataSource.indexPath(for: item) {
|
let indexPath = self.dataSource.indexPath(for: firstItem) {
|
||||||
// maintain the current position in the list (don't scroll to top)
|
// maintain the current position in the list (don't scroll to top)
|
||||||
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
|
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
|
||||||
}
|
}
|
||||||
|
@ -265,11 +269,11 @@ class DiffableTimelineLikeTableViewController<Section: Hashable & CaseIterable,
|
||||||
fatalError("loadInitialItems(completion:) must be implemented by subclasses")
|
fatalError("loadInitialItems(completion:) must be implemented by subclasses")
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadOlderItems(currentSnapshot: Snapshot, completion: @escaping (LoadResult) -> Void) {
|
func loadOlderItems(currentSnapshot: @escaping () -> Snapshot, completion: @escaping (LoadResult) -> Void) {
|
||||||
fatalError("loadOlderItesm(completion:) must be implemented by subclasses")
|
fatalError("loadOlderItesm(completion:) must be implemented by subclasses")
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadNewerItems(currentSnapshot: Snapshot, completion: @escaping (LoadResult) -> Void) {
|
func loadNewerItems(currentSnapshot: @escaping () -> Snapshot, completion: @escaping (LoadResult) -> Void) {
|
||||||
fatalError("loadNewerItems(completion:) must be implemented by subclasses")
|
fatalError("loadNewerItems(completion:) must be implemented by subclasses")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue