1 contributor
//
// AppDelegate.swift
// USB Meter
//
// Created by Bogdan Timofte on 01/03/2020.
// Copyright © 2020 Bogdan Timofte. All rights reserved.
//
import UIKit
import CoreData
import CloudKit
//let btSerial = BluetoothSerial(delegate: BSD())
let appData = AppData()
enum Constants {
static let chartUnderscan: CGFloat = 0.5
static let chartOverscan: CGFloat = 1 - chartUnderscan
}
// MARK: Clock
// MARK: Debug
public func track(_ message: String = "", file: String = #file, function: String = #function, line: Int = #line ) {
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let seconds = calendar.component(.second, from: date)
print("\(hour):\(minutes):\(seconds) - \(file):\(line) - \(function) \(message)")
}
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let cloudKitContainerIdentifier = "iCloud.ro.xdev.USB-Meter"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
logCloudKitStatus()
return true
}
private func logCloudKitStatus() {
let container = CKContainer(identifier: cloudKitContainerIdentifier)
container.accountStatus { status, error in
if let error {
track("CloudKit account status error: \(error.localizedDescription)")
return
}
let statusDescription: String
switch status {
case .available:
statusDescription = "available"
case .noAccount:
statusDescription = "noAccount"
case .restricted:
statusDescription = "restricted"
case .couldNotDetermine:
statusDescription = "couldNotDetermine"
case .temporarilyUnavailable:
statusDescription = "temporarilyUnavailable"
@unknown default:
statusDescription = "unknown"
}
track("CloudKit account status for \(self.cloudKitContainerIdentifier): \(statusDescription)")
}
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentCloudKitContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentCloudKitContainer(name: "CKModel")
if let description = container.persistentStoreDescriptions.first {
description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.ro.xdev.USB-Meter")
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Log error and attempt recovery instead of crashing the app immediately.
NSLog("Core Data store load failed: %s", error.localizedDescription)
// Attempt lightweight migration and fallback by resetting the store when migration fails.
if let storeURL = storeDescription.url {
let coordinator = container.persistentStoreCoordinator
let storeType = storeDescription.type
do {
try coordinator.destroyPersistentStore(at: storeURL, ofType: storeType, options: nil)
try coordinator.addPersistentStore(ofType: storeType, configurationName: nil, at: storeURL, options: storeDescription.options)
NSLog("Core Data store recovered by destroying and recreating store at %@", storeURL.path)
return
} catch {
NSLog("Core Data recovery attempt failed: %s", (error as NSError).localizedDescription)
}
}
// As a last resort, keep running but note that persistent store is unavailable.
// In debug environment this should be investigated further.
#if DEBUG
fatalError("Unresolved error \(error), \(error.userInfo)")
#endif
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
NSLog("Core Data save failed: %@", nserror.localizedDescription)
#if DEBUG
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
#endif
}
}
}
}