From bde21fbc6cae4d921f96b5af7c79ec92ce8410ea Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 24 Oct 2023 15:28:44 -0400 Subject: [PATCH] Fix crash due to prematurely pruned statuses being fetched If the app hasn't launched in long enough, we may be displaying old statuses as a result of state restoration. If the user leaves the app, those statuses can't get pruned, because the user may return. We need to make sure the lastFetchedAt date is current, since awakeFromFetch won't be called until the object is faulted in (which wasn't happening immediately during state restoration). --- Tusker/CoreData/AccountMO.swift | 7 ++++++- Tusker/CoreData/StatusMO.swift | 7 ++++++- Tusker/Screens/Timeline/TimelineViewController.swift | 10 +++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Tusker/CoreData/AccountMO.swift b/Tusker/CoreData/AccountMO.swift index df237ecc..a3df7ba1 100644 --- a/Tusker/CoreData/AccountMO.swift +++ b/Tusker/CoreData/AccountMO.swift @@ -59,9 +59,14 @@ public final class AccountMO: NSManagedObject, AccountProtocol { super.awakeFromFetch() managedObjectContext?.perform { - self.lastFetchedAt = Date() + self.touch() } } + + /// Update the `lastFetchedAt` date so this object isn't pruned early. + func touch() { + lastFetchedAt = Date() + } } diff --git a/Tusker/CoreData/StatusMO.swift b/Tusker/CoreData/StatusMO.swift index 774f8726..e37f64e5 100644 --- a/Tusker/CoreData/StatusMO.swift +++ b/Tusker/CoreData/StatusMO.swift @@ -89,10 +89,15 @@ public final class StatusMO: NSManagedObject, StatusProtocol { super.awakeFromFetch() managedObjectContext?.perform { - self.lastFetchedAt = Date() + self.touch() } } + /// Update the `lastFetchedAt` date so this object isn't pruned early. + func touch() { + lastFetchedAt = Date() + } + } extension StatusMO { diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index f27349f2..e8096cf4 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -440,7 +440,15 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro private func loadStatusesToRestore(position: TimelinePosition) async -> Bool { let originalPositionStatusIDs = position.statusIDs - let unloaded = position.statusIDs.filter({ mastodonController.persistentContainer.status(for: $0) == nil }) + var unloaded = [String]() + for id in position.statusIDs { + if let status = mastodonController.persistentContainer.status(for: id) { + // touch the status so that, even if it's old, it doesn't get pruned when we go into the background + status.touch() + } else { + unloaded.append(id) + } + } guard !unloaded.isEmpty else { return true }