USB-Meter / USB Meter / AppDelegate.swift
1 contributor
148 lines | 6.432kb
//
//  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
            }
        }
    }

}