Skip to content

Commit 1f07c00

Browse files
committed
bugfixes: improve Core Data handling and eliminate crash
1 parent adde65c commit 1f07c00

4 files changed

Lines changed: 83 additions & 62 deletions

File tree

InfiniLink/BLE/DeviceManager.swift

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,29 +92,31 @@ class DeviceManager: ObservableObject {
9292
fetchRequest.predicate = NSPredicate(format: "uuid == %@", id)
9393

9494
do {
95-
let context = persistenceController.container.viewContext
96-
let existingDevices = try context.fetch(fetchRequest)
95+
let existingDevices = try persistenceController.container.viewContext.fetch(fetchRequest)
9796

9897
// There's already a paired watch
9998
if let existingDevice = existingDevices.first {
10099
return existingDevice
101100
}
102101

103102
// There's not already a paired watch, create a new object to save
103+
let context = persistenceController.container.newBackgroundContext()
104104
let newDevice = Device(context: context)
105-
newDevice.uuid = id
106-
newDevice.bleUUID = id
107-
newDevice.blefsVersion = ""
108-
newDevice.firmware = ""
109-
newDevice.softwareRevision = ""
110-
newDevice.hardwareRevision = ""
111-
newDevice.manufacturer = ""
112-
newDevice.modelNumber = ""
113-
newDevice.serial = ""
114-
115-
Task {
116-
try await context.perform {
105+
context.perform {
106+
newDevice.uuid = id
107+
newDevice.bleUUID = id
108+
newDevice.blefsVersion = ""
109+
newDevice.firmware = ""
110+
newDevice.softwareRevision = ""
111+
newDevice.hardwareRevision = ""
112+
newDevice.manufacturer = ""
113+
newDevice.modelNumber = ""
114+
newDevice.serial = ""
115+
116+
do {
117117
try context.save()
118+
} catch {
119+
log("Error saving new device: \(error.localizedDescription)", caller: "DeviceManager - fetchDevice")
118120
}
119121
}
120122

@@ -188,17 +190,13 @@ class DeviceManager: ObservableObject {
188190
}
189191

190192
func removeDevice(_ device: Device) {
191-
let context = persistenceController.container.viewContext
193+
let context = persistenceController.container.newBackgroundContext()
192194

193-
Task {
194-
await context.perform {
195-
do {
196-
context.delete(device)
197-
try context.save()
198-
} catch {
199-
log(error.localizedDescription, caller: "DeviceManager - removeDevice")
200-
}
201-
}
195+
do {
196+
context.delete(device)
197+
try context.save()
198+
} catch {
199+
log("Error removing device: \(error.localizedDescription)", caller: "DeviceManager")
202200
}
203201
}
204202

InfiniLink/Core/DeviceView.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import SwiftUI
99

1010
struct DeviceView: View {
1111
@Environment(\.openURL) var openURL
12+
@Environment(\.scenePhase) private var scenePhase
1213

1314
@ObservedObject var bleManager = BLEManager.shared
1415
@ObservedObject var deviceManager = DeviceManager.shared
@@ -182,12 +183,10 @@ struct DeviceView: View {
182183
} label: {
183184
ListRowView(title: "Notifications", icon: "bell.badge.fill", iconColor: .red)
184185
}
185-
if #available(iOS 17, *) {
186-
NavigationLink {
187-
DirectionsView()
188-
} label: {
189-
ListRowView(title: "Navigation", icon: "map.fill", iconColor: .blue)
190-
}
186+
NavigationLink {
187+
DirectionsView()
188+
} label: {
189+
ListRowView(title: "Navigation", icon: "map.fill", iconColor: .blue)
191190
}
192191
NavigationLink {
193192
WeatherView()
@@ -225,15 +224,23 @@ struct DeviceView: View {
225224
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { values in
226225
guard let value = values.first else { return }
227226

228-
self.showNavigationTitle = (value <= -135)
227+
withAnimation(.easeInOut(duration: 0.4)) {
228+
self.showNavigationTitle = (value <= -135)
229+
}
229230
}
230231
.onChange(of: bleManager.blefsTransfer) { blefsTransfer in
231-
if blefsTransfer != nil {
232+
if blefsTransfer != nil && scenePhase == .active {
232233
BLEFSHandler.shared.readSettings { settings in
234+
// MARK: - Candidate
235+
// This is getting called while in the background, and fetching/updating objects from the UI/main thread, and could be the source of crashes
236+
// We need to add a check to make sure we're in the foreground when we call this method
233237
deviceManager.updateSettings(settings: settings)
234238
}
235239
}
236240
}
241+
.onChange(of: scenePhase) { phase in
242+
log("Phase changed to \(phase)", type: .info, caller: "DeviceView")
243+
}
237244
.onAppear {
238245
if let pairedDeviceID = bleManager.pairedDeviceID {
239246
bleManager.pairedDevice = deviceManager.fetchDevice(with: pairedDeviceID)

InfiniLink/Utils/ChartManager.swift

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,50 @@ class ChartManager: ObservableObject {
1919
static let shared = ChartManager()
2020

2121
func addStepDataPoint(steps: Int32, time: Date) {
22-
let heartRateDataPoint = StepCounts(context: persistenceController.container.viewContext)
23-
heartRateDataPoint.steps = steps
24-
heartRateDataPoint.timestamp = time
25-
heartRateDataPoint.deviceId = bleManager.pairedDeviceID
26-
27-
Task {
28-
await persistenceController.save()
22+
let context = persistenceController.container.newBackgroundContext()
23+
context.perform {
24+
let heartRateDataPoint = StepCounts(context: context)
25+
heartRateDataPoint.steps = steps
26+
heartRateDataPoint.timestamp = time
27+
heartRateDataPoint.deviceId = self.bleManager.pairedDeviceID
28+
29+
do {
30+
try context.save()
31+
} catch {
32+
log("Error saving step point: \(error.localizedDescription)")
33+
}
2934
}
3035
}
3136

3237
func addHeartRateDataPoint(heartRate: Double, time: Date) {
33-
let heartRateDataPoint = HeartDataPoint(context: persistenceController.container.viewContext)
34-
heartRateDataPoint.value = heartRate
35-
heartRateDataPoint.timestamp = time
36-
heartRateDataPoint.deviceId = bleManager.pairedDeviceID
37-
38-
Task {
39-
await persistenceController.save()
38+
let context = persistenceController.container.newBackgroundContext()
39+
context.perform {
40+
let heartRateDataPoint = HeartDataPoint(context: context)
41+
heartRateDataPoint.value = heartRate
42+
heartRateDataPoint.timestamp = time
43+
heartRateDataPoint.deviceId = self.bleManager.pairedDeviceID
44+
45+
do {
46+
try context.save()
47+
} catch {
48+
log("Error saving heart point: \(error.localizedDescription)")
49+
}
4050
}
4151
}
4252

4353
func addBatteryDataPoint(batteryLevel: Double, time: Date) {
44-
let batteryDataPoint = BatteryDataPoint(context: persistenceController.container.viewContext)
45-
batteryDataPoint.value = batteryLevel
46-
batteryDataPoint.timestamp = time
47-
batteryDataPoint.deviceId = bleManager.pairedDeviceID
48-
49-
Task {
50-
await persistenceController.save()
54+
let context = persistenceController.container.newBackgroundContext()
55+
context.perform {
56+
let batteryDataPoint = BatteryDataPoint(context: context)
57+
batteryDataPoint.value = batteryLevel
58+
batteryDataPoint.timestamp = time
59+
batteryDataPoint.deviceId = self.bleManager.pairedDeviceID
60+
61+
do {
62+
try context.save()
63+
} catch {
64+
log("Error saving battery point: \(error.localizedDescription)")
65+
}
5166
}
5267
}
5368

@@ -115,17 +130,17 @@ class ChartManager: ObservableObject {
115130
}
116131

117132
func deleteAllUserExercises() {
118-
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = UserExercise.fetchRequest()
119-
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
120-
121-
do {
122-
try persistenceController.container.viewContext.execute(batchDeleteRequest)
133+
let context = persistenceController.container.newBackgroundContext()
134+
context.perform {
135+
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = UserExercise.fetchRequest()
136+
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
123137

124-
Task {
125-
await persistenceController.save()
138+
do {
139+
try context.execute(batchDeleteRequest)
140+
try context.save()
141+
} catch {
142+
log("Failed to delete user exercises: \(error)", caller: "ChartManager")
126143
}
127-
} catch {
128-
log("Failed to delete user exercises: \(error)", caller: "ChartManager")
129144
}
130145
}
131146
}

InfiniLink/Utils/StepCountManager.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class StepCountManager: ObservableObject {
2121
return BLEManager.shared.stepCount >= stepGoal
2222
}
2323

24+
// The following two functions need to use the viewContext to save because the objects they're updating were fetched on that context
2425
func setStepCount(steps: Int32, isArbitrary: Bool, for date: Date) {
2526
let existingCounts = chartManager.stepPoints()
2627

0 commit comments

Comments
 (0)