Selaa lähdekoodia

Log fatal crashes and present alert on next launch

pull/212/head
Angelo Stavrow 1 vuosi sitten
vanhempi
commit
5a1b400333
No known key found for this signature in database GPG Key ID: 1A49C7064E060EEE
4 muutettua tiedostoa jossa 72 lisäystä ja 8 poistoa
  1. +2
    -0
      Shared/Extensions/UserDefaults+Extensions.swift
  2. +33
    -6
      Shared/LocalStorageManager.swift
  3. +19
    -2
      Shared/PostCollection/CollectionListModel.swift
  4. +18
    -0
      Shared/WriteFreely_MultiPlatformApp.swift

+ 2
- 0
Shared/Extensions/UserDefaults+Extensions.swift Näytä tiedosto

@@ -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 {


+ 33
- 6
Shared/LocalStorageManager.swift Näytä tiedosto

@@ -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)
}

}

+ 19
- 2
Shared/PostCollection/CollectionListModel.swift Näytä tiedosto

@@ -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()


+ 18
- 0
Shared/WriteFreely_MultiPlatformApp.swift Näytä tiedosto

@@ -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)


Ladataan…
Peruuta
Tallenna