From cce6413e2beb93dfb1f00dfb5fcc03c399ad1305 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 8 Jan 2023 17:56:21 -0400 Subject: [PATCH] Fix crash when trying to load deleted statuses for restoration --- .../Timeline/TimelineViewController.swift | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index 9a4b208c..c63a8db3 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -334,25 +334,31 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro return false } loadViewIfNeeded() + var loaded = false await controller.restoreInitial { - await loadStatusesToRestore(position: position) - applyItemsToRestore(position: position) + let hasStatusesToRestore = await loadStatusesToRestore(position: position) + if hasStatusesToRestore { + applyItemsToRestore(position: position) + loaded = true + } } - return true + return loaded } @MainActor - private func loadStatusesToRestore(position: TimelinePosition) async { + private func loadStatusesToRestore(position: TimelinePosition) async -> Bool { let unloaded = position.statusIDs.filter({ mastodonController.persistentContainer.status(for: $0) == nil }) guard !unloaded.isEmpty else { - return + return true } let statuses = await withTaskGroup(of: Status?.self) { group -> [Status] in for id in unloaded { - group.addTask { @MainActor in - if let (status, _) = try? await self.mastodonController.run(Client.getStatus(id: id)) { + group.addTask { + do { + let (status, _) = try await self.mastodonController.run(Client.getStatus(id: id)) return status - } else { + } catch { + print(error) return nil } } @@ -364,6 +370,20 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro } } await mastodonController.persistentContainer.addAll(statuses: statuses, in: mastodonController.persistentContainer.viewContext) + + // update the timeline position in case some statuses couldn't be loaded + if let center = position.centerStatusID { + let nearestLoadedStatusToCenter = position.statusIDs[position.statusIDs.firstIndex(of: center)!...].first(where: { id in + // was already loaded or was just now loaded + !unloaded.contains(id) || statuses.contains(where: { $0.id == id }) + }) + position.centerStatusID = nearestLoadedStatusToCenter + } + position.statusIDs = position.statusIDs.filter { id in + !unloaded.contains(id) || statuses.contains(where: { $0.id == id }) + } + + return !position.statusIDs.isEmpty } private func applyItemsToRestore(position: TimelinePosition) {