USB-Meter / USB Meter / AppDelegate.swift
Newer Older
148 lines | 6.432kb
Bogdan Timofte authored 2 weeks ago
1
//
2
//  AppDelegate.swift
3
//  USB Meter
4
//
5
//  Created by Bogdan Timofte on 01/03/2020.
6
//  Copyright © 2020 Bogdan Timofte. All rights reserved.
7
//
8

            
9
import UIKit
10
import CoreData
Bogdan Timofte authored 2 weeks ago
11
import CloudKit
Bogdan Timofte authored 2 weeks ago
12

            
13
//let btSerial = BluetoothSerial(delegate: BSD())
14
let appData = AppData()
15
enum Constants {
16
    static let chartUnderscan: CGFloat = 0.5
17
    static let chartOverscan: CGFloat = 1 - chartUnderscan
18
}
19
// MARK: Clock
20

            
21
// MARK: Debug
22
public func track(_ message: String = "", file: String = #file, function: String = #function, line: Int = #line ) {
23
    let date = Date()
24
    let calendar = Calendar.current
25
    let hour = calendar.component(.hour, from: date)
26
    let minutes = calendar.component(.minute, from: date)
27
    let seconds = calendar.component(.second, from: date)
28
    print("\(hour):\(minutes):\(seconds) - \(file):\(line) - \(function) \(message)")
29
}
30

            
31
@UIApplicationMain
32
class AppDelegate: UIResponder, UIApplicationDelegate {
33

            
Bogdan Timofte authored 2 weeks ago
34
    private let cloudKitContainerIdentifier = "iCloud.ro.xdev.USB-Meter"
35

            
Bogdan Timofte authored 2 weeks ago
36

            
37
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
38
        // Override point for customization after application launch.
Bogdan Timofte authored 2 weeks ago
39
        logCloudKitStatus()
Bogdan Timofte authored 2 weeks ago
40
        return true
41
    }
42

            
Bogdan Timofte authored 2 weeks ago
43
    private func logCloudKitStatus() {
44
        let container = CKContainer(identifier: cloudKitContainerIdentifier)
45
        container.accountStatus { status, error in
46
            if let error {
47
                track("CloudKit account status error: \(error.localizedDescription)")
48
                return
49
            }
50
            let statusDescription: String
51
            switch status {
52
            case .available:
53
                statusDescription = "available"
54
            case .noAccount:
55
                statusDescription = "noAccount"
56
            case .restricted:
57
                statusDescription = "restricted"
58
            case .couldNotDetermine:
59
                statusDescription = "couldNotDetermine"
60
            case .temporarilyUnavailable:
61
                statusDescription = "temporarilyUnavailable"
62
            @unknown default:
63
                statusDescription = "unknown"
64
            }
65
            track("CloudKit account status for \(self.cloudKitContainerIdentifier): \(statusDescription)")
66
        }
67
    }
68

            
Bogdan Timofte authored 2 weeks ago
69
    // MARK: UISceneSession Lifecycle
70

            
71
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
72
        // Called when a new scene session is being created.
73
        // Use this method to select a configuration to create the new scene with.
74
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
75
    }
76

            
77
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
78
        // Called when the user discards a scene session.
79
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
80
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
81
    }
82

            
83
    // MARK: - Core Data stack
84

            
85
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
86
        /*
87
         The persistent container for the application. This implementation
88
         creates and returns a container, having loaded the store for the
89
         application to it. This property is optional since there are legitimate
90
         error conditions that could cause the creation of the store to fail.
91
        */
92
        let container = NSPersistentCloudKitContainer(name: "CKModel")
Bogdan Timofte authored 2 weeks ago
93
        if let description = container.persistentStoreDescriptions.first {
94
            description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.ro.xdev.USB-Meter")
95
            description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
96
            description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
97
        }
Bogdan Timofte authored 2 weeks ago
98
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
99
            if let error = error as NSError? {
Bogdan Timofte authored 2 weeks ago
100
                // Log error and attempt recovery instead of crashing the app immediately.
101
                NSLog("Core Data store load failed: %s", error.localizedDescription)
102

            
103
                // Attempt lightweight migration and fallback by resetting the store when migration fails.
104
                if let storeURL = storeDescription.url {
105
                    let coordinator = container.persistentStoreCoordinator
106
                    let storeType = storeDescription.type
107
                    do {
108
                        try coordinator.destroyPersistentStore(at: storeURL, ofType: storeType, options: nil)
109
                        try coordinator.addPersistentStore(ofType: storeType, configurationName: nil, at: storeURL, options: storeDescription.options)
110
                        NSLog("Core Data store recovered by destroying and recreating store at %@", storeURL.path)
111
                        return
112
                    } catch {
113
                        NSLog("Core Data recovery attempt failed: %s", (error as NSError).localizedDescription)
114
                    }
115
                }
116

            
117
                // As a last resort, keep running but note that persistent store is unavailable.
118
                // In debug environment this should be investigated further.
119
                #if DEBUG
Bogdan Timofte authored 2 weeks ago
120
                fatalError("Unresolved error \(error), \(error.userInfo)")
Bogdan Timofte authored 2 weeks ago
121
                #endif
Bogdan Timofte authored 2 weeks ago
122
            }
123
        })
Bogdan Timofte authored 2 weeks ago
124
        container.viewContext.automaticallyMergesChangesFromParent = true
125
        container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
Bogdan Timofte authored 2 weeks ago
126
        return container
127
    }()
128

            
129
    // MARK: - Core Data Saving support
130

            
131
    func saveContext () {
132
        let context = persistentContainer.viewContext
133
        if context.hasChanges {
134
            do {
135
                try context.save()
136
            } catch {
137
                let nserror = error as NSError
Bogdan Timofte authored 2 weeks ago
138
                NSLog("Core Data save failed: %@", nserror.localizedDescription)
139

            
140
                #if DEBUG
Bogdan Timofte authored 2 weeks ago
141
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
Bogdan Timofte authored 2 weeks ago
142
                #endif
Bogdan Timofte authored 2 weeks ago
143
            }
144
        }
145
    }
146

            
147
}
148