mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Log fatal crashes and present alert on next launch
This commit is contained in:
parent
a43bd801a8
commit
5a1b400333
@ -13,6 +13,8 @@ enum WFDefaults {
|
||||
static let automaticallyChecksForUpdates = "automaticallyChecksForUpdates"
|
||||
static let subscribeToBetaUpdates = "subscribeToBetaUpdates"
|
||||
#endif
|
||||
static let didHaveFatalError = "didHaveFatalError"
|
||||
static let fatalErrorDescription = "fatalErrorDescription"
|
||||
}
|
||||
|
||||
extension UserDefaults {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import CoreData
|
||||
import os
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
@ -21,9 +22,11 @@ final class LocalStorageManager {
|
||||
func saveContext() {
|
||||
if container.viewContext.hasChanges {
|
||||
do {
|
||||
Self.logger.info("Saving context to local store started...")
|
||||
try container.viewContext.save()
|
||||
Self.logger.notice("Context saved to local store.")
|
||||
} catch {
|
||||
fatalError(LocalStoreError.couldNotSaveContext.localizedDescription)
|
||||
logCrashAndSetFlag(error: LocalStoreError.couldNotSaveContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,8 +36,11 @@ final class LocalStorageManager {
|
||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
|
||||
|
||||
do {
|
||||
Self.logger.info("Purging user collections from local store...")
|
||||
try container.viewContext.executeAndMergeChanges(using: deleteRequest)
|
||||
Self.logger.notice("User collections purged from local store.")
|
||||
} catch {
|
||||
Self.logger.error("\(LocalStoreError.couldNotPurgeCollections.localizedDescription)")
|
||||
throw LocalStoreError.couldNotPurgeCollections
|
||||
}
|
||||
}
|
||||
@ -60,9 +66,11 @@ private extension LocalStorageManager {
|
||||
}
|
||||
|
||||
container.loadPersistentStores { _, error in
|
||||
Self.logger.info("Loading local store...")
|
||||
if let error = error {
|
||||
fatalError(LocalStoreError.couldNotLoadStore(error.localizedDescription).localizedDescription)
|
||||
self.logCrashAndSetFlag(error: LocalStoreError.couldNotLoadStore(error.localizedDescription))
|
||||
}
|
||||
Self.logger.notice("Loaded local store.")
|
||||
}
|
||||
migrateStore(for: container)
|
||||
container.viewContext.automaticallyMergesChangesFromParent = true
|
||||
@ -83,21 +91,23 @@ private extension LocalStorageManager {
|
||||
|
||||
// Attempt to migrate the old store over to the shared store URL.
|
||||
do {
|
||||
Self.logger.info("Migrating local store to shared store...")
|
||||
try coordinator.migratePersistentStore(oldStore,
|
||||
to: sharedStoreURL,
|
||||
options: nil,
|
||||
withType: NSSQLiteStoreType)
|
||||
Self.logger.notice("Migrated local store to shared store.")
|
||||
} catch {
|
||||
fatalError(LocalStoreError.couldNotMigrateStore(error.localizedDescription).localizedDescription)
|
||||
logCrashAndSetFlag(error: LocalStoreError.couldNotMigrateStore(error.localizedDescription))
|
||||
}
|
||||
|
||||
// Attempt to delete the old store.
|
||||
do {
|
||||
Self.logger.info("Deleting migrated local store...")
|
||||
try FileManager.default.removeItem(at: oldStoreURL)
|
||||
Self.logger.notice("Deleted migrated local store.")
|
||||
} catch {
|
||||
fatalError(
|
||||
LocalStoreError.couldNotDeleteStoreAfterMigration(error.localizedDescription).localizedDescription
|
||||
)
|
||||
logCrashAndSetFlag(error: LocalStoreError.couldNotDeleteStoreAfterMigration(error.localizedDescription))
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,3 +133,20 @@ private extension LocalStorageManager {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension LocalStorageManager {
|
||||
|
||||
private static let logger = Logger(
|
||||
subsystem: Bundle.main.bundleIdentifier!,
|
||||
category: String(describing: LocalStorageManager.self)
|
||||
)
|
||||
|
||||
private func logCrashAndSetFlag(error: Error) {
|
||||
let errorDescription = error.localizedDescription
|
||||
UserDefaults.shared.set(true, forKey: WFDefaults.didHaveFatalError)
|
||||
UserDefaults.shared.set(errorDescription, forKey: WFDefaults.fatalErrorDescription)
|
||||
Self.logger.critical("\(errorDescription)")
|
||||
fatalError(errorDescription)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import os
|
||||
|
||||
class CollectionListModel: NSObject, ObservableObject {
|
||||
@Published var list: [WFACollection] = []
|
||||
@ -16,11 +17,12 @@ class CollectionListModel: NSObject, ObservableObject {
|
||||
collectionsController.delegate = self
|
||||
|
||||
do {
|
||||
Self.logger.info("Fetching collections from local store...")
|
||||
try collectionsController.performFetch()
|
||||
list = collectionsController.fetchedObjects ?? []
|
||||
Self.logger.notice("Fetched collections from local store.")
|
||||
} catch {
|
||||
// FIXME: Errors cannot be thrown out of the CollectionListView property initializer
|
||||
fatalError(LocalStoreError.couldNotFetchCollections.localizedDescription)
|
||||
logCrashAndSetFlag(error: LocalStoreError.couldNotFetchCollections)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,6 +34,21 @@ extension CollectionListModel: NSFetchedResultsControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
extension CollectionListModel {
|
||||
private static let logger = Logger(
|
||||
subsystem: Bundle.main.bundleIdentifier!,
|
||||
category: String(describing: CollectionListModel.self)
|
||||
)
|
||||
|
||||
private func logCrashAndSetFlag(error: Error) {
|
||||
let errorDescription = error.localizedDescription
|
||||
UserDefaults.shared.set(true, forKey: WFDefaults.didHaveFatalError)
|
||||
UserDefaults.shared.set(errorDescription, forKey: WFDefaults.fatalErrorDescription)
|
||||
Self.logger.critical("\(errorDescription)")
|
||||
fatalError(errorDescription)
|
||||
}
|
||||
}
|
||||
|
||||
extension WFACollection {
|
||||
static var collectionsFetchRequest: NSFetchRequest<WFACollection> {
|
||||
let request: NSFetchRequest<WFACollection> = WFACollection.createFetchRequest()
|
||||
|
@ -30,6 +30,8 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
@State private var selectedTab = 0
|
||||
#endif
|
||||
|
||||
@State private var didCrash = UserDefaults.shared.bool(forKey: WFDefaults.didHaveFatalError)
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
@ -48,6 +50,22 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
}
|
||||
}
|
||||
})
|
||||
.alert(isPresented: $didCrash) {
|
||||
// TODO: - Confirm copy for this alert
|
||||
Alert(
|
||||
title: Text("Crash Detected"),
|
||||
message: Text(
|
||||
UserDefaults.shared.object(forKey: WFDefaults.fatalErrorDescription) as? String ??
|
||||
"Something went horribly wrong!"
|
||||
),
|
||||
dismissButton: .default(
|
||||
Text("Dismiss"), action: {
|
||||
UserDefaults.shared.set(false, forKey: WFDefaults.didHaveFatalError)
|
||||
UserDefaults.shared.removeObject(forKey: WFDefaults.fatalErrorDescription)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
.withErrorHandling()
|
||||
.environmentObject(model)
|
||||
.environment(\.managedObjectContext, LocalStorageManager.standard.container.viewContext)
|
||||
|
Loading…
Reference in New Issue
Block a user