From d4c560d7fc22f2e680d7df1353b76ba6e3c591e5 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 1 Jan 2023 12:58:44 -0500 Subject: [PATCH] Add createdAt to AccountPreferences and TimelinePosition to guard against race conditions when creating/migrating --- Tusker/API/MastodonController.swift | 24 ++++++++++++++----- Tusker/CoreData/AccountPreferences.swift | 3 +++ Tusker/CoreData/TimelinePosition.swift | 3 +++ .../Tusker.xcdatamodel/contents | 4 +++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Tusker/API/MastodonController.swift b/Tusker/API/MastodonController.swift index 4af44b46..9dfbd0e6 100644 --- a/Tusker/API/MastodonController.swift +++ b/Tusker/API/MastodonController.swift @@ -155,12 +155,14 @@ class MastodonController: ObservableObject { // are available when Filterers are constructed loadCachedFilters() - if let existing = try? persistentContainer.viewContext.fetch(AccountPreferences.fetchRequest(account: accountInfo!)).first { - accountPreferences = existing - } else { - accountPreferences = AccountPreferences.default(account: accountInfo!, context: persistentContainer.viewContext) - persistentContainer.save(context: persistentContainer.viewContext) - } + loadAccountPreferences() + + NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange, object: persistentContainer.persistentStoreCoordinator) + .receive(on: DispatchQueue.main) + .sink { [unowned self] _ in + self.loadAccountPreferences() + } + .store(in: &cancellables) Task { do { @@ -177,6 +179,16 @@ class MastodonController: ObservableObject { } } + @MainActor + private func loadAccountPreferences() { + if let existing = try? persistentContainer.viewContext.fetch(AccountPreferences.fetchRequest(account: accountInfo!)).first { + accountPreferences = existing + } else { + accountPreferences = AccountPreferences.default(account: accountInfo!, context: persistentContainer.viewContext) + persistentContainer.save(context: persistentContainer.viewContext) + } + } + func getOwnAccount(completion: ((Result) -> Void)? = nil) { if account != nil { completion?(.success(account)) diff --git a/Tusker/CoreData/AccountPreferences.swift b/Tusker/CoreData/AccountPreferences.swift index ebce929c..2f648380 100644 --- a/Tusker/CoreData/AccountPreferences.swift +++ b/Tusker/CoreData/AccountPreferences.swift @@ -16,10 +16,12 @@ public final class AccountPreferences: NSManagedObject { @nonobjc class func fetchRequest(account: LocalData.UserAccountInfo) -> NSFetchRequest { let req = NSFetchRequest(entityName: "AccountPreferences") req.predicate = NSPredicate(format: "accountID = %@", account.id) + req.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: true)] return req } @NSManaged public var accountID: String + @NSManaged var createdAt: Date @NSManaged var pinnedTimelinesData: Data? @LazilyDecoding(from: \AccountPreferences.pinnedTimelinesData, fallback: []) @@ -28,6 +30,7 @@ public final class AccountPreferences: NSManagedObject { static func `default`(account: LocalData.UserAccountInfo, context: NSManagedObjectContext) -> AccountPreferences { let prefs = AccountPreferences(context: context) prefs.accountID = account.id + prefs.createdAt = Date() prefs.pinnedTimelines = [.home, .public(local: true), .public(local: false)] return prefs } diff --git a/Tusker/CoreData/TimelinePosition.swift b/Tusker/CoreData/TimelinePosition.swift index a4756dd6..d093c114 100644 --- a/Tusker/CoreData/TimelinePosition.swift +++ b/Tusker/CoreData/TimelinePosition.swift @@ -16,10 +16,12 @@ public final class TimelinePosition: NSManagedObject { @nonobjc class func fetchRequest(timeline: Timeline, account: LocalData.UserAccountInfo) -> NSFetchRequest { let req = NSFetchRequest(entityName: "TimelinePosition") req.predicate = NSPredicate(format: "accountID = %@ AND timelineKind = %@", account.id, toTimelineKind(timeline)) + req.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: true)] return req } @NSManaged public var accountID: String + @NSManaged public var createdAt: Date @NSManaged private var timelineKind: String @NSManaged public var centerStatusID: String? @NSManaged private var statusIDsData: Data? @@ -36,6 +38,7 @@ public final class TimelinePosition: NSManagedObject { self.init(context: context) self.timeline = timeline self.accountID = account.id + self.createdAt = Date() } } diff --git a/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents b/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents index a3e87bf8..e2fe0656 100644 --- a/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents +++ b/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -30,6 +30,7 @@ + @@ -120,6 +121,7 @@ +