@@ -75,19 +75,23 @@ final class NavDataLoaderViewModel: WithIdentifiableError {
7575 )
7676
7777 addTask (
78- Task {
78+ Task . detached { [ container ] in
7979 do {
80- let context = container. mainContext
81- try setAnyAirports ( context: context)
80+ let context = ModelContext ( container)
8281 while !Task. isCancelled {
83- try setAnyAirports ( context: context)
82+ let state = try NavDataStateHelper . fetchState ( context: context)
83+ await MainActor . run {
84+ self . applyState ( state)
85+ }
8486 try ? await Task . sleep ( for: . seconds( 0.5 ) )
8587 }
8688 } catch {
87- SentrySDK . capture ( error: error) { scope in
88- scope. setFingerprint ( [ " navData " , " airportCheck " ] )
89+ await MainActor . run {
90+ SentrySDK . capture ( error: error) { scope in
91+ scope. setFingerprint ( [ " navData " , " airportCheck " ] )
92+ }
93+ self . error = error
8994 }
90- self . error = error
9195 }
9296 }
9397 )
@@ -182,25 +186,40 @@ final class NavDataLoaderViewModel: WithIdentifiableError {
182186 Defaults [ . ourAirportsLastUpdated] = nil
183187 }
184188
185- private func outOfDate ( expirationDate : Date ? ) -> Bool {
186- guard let expirationDate else { return true }
187- return Date ( ) > expirationDate
189+ private func recalculate ( ) throws {
190+ let state = try NavDataStateHelper . fetchState ( context : container . mainContext )
191+ applyState ( state )
188192 }
189193
190- private func outOfDate( schemaVersion: Int ) -> Bool {
191- schemaVersion != latestSchemaVersion
194+ private func applyState( _ state: NavDataStateHelper . State ) {
195+ if noData != state. noData { self . noData = state. noData }
196+ if needsLoad != state. needsLoad { self . needsLoad = state. needsLoad }
197+ if canSkip != state. canSkip { self . canSkip = state. canSkip }
192198 }
199+ }
193200
194- private func recalculate( ) throws {
195- let schemaOutOfDate = outOfDate ( schemaVersion: Defaults [ . schemaVersion] )
196- let nasrExpiration = try fetchNASRExpiration ( )
197- let dataOutOfDate = outOfDate ( expirationDate: nasrExpiration)
198- needsLoad = schemaOutOfDate || dataOutOfDate
199- canSkip = !noData && !schemaOutOfDate
201+ /// File-scope helper for computing nav-data loader state from any `ModelContext`.
202+ ///
203+ /// Declared outside `NavDataLoaderViewModel` so it is nonisolated by default
204+ /// and callable from both MainActor and background tasks without annotations.
205+ private enum NavDataStateHelper {
206+ static func fetchState( context: ModelContext ) throws -> State {
207+ var airportDescriptor = FetchDescriptor < SF50_Shared . Airport > ( )
208+ airportDescriptor. fetchLimit = 1
209+ let noData = try context. fetch ( airportDescriptor) . isEmpty
210+
211+ let schemaOutOfDate = Defaults [ . schemaVersion] != latestSchemaVersion
212+ let nasrExpiration = try fetchNASRExpiration ( context: context)
213+ let dataOutOfDate = nasrExpiration. map { Date ( ) > $0 } ?? true
214+
215+ return State (
216+ noData: noData,
217+ needsLoad: schemaOutOfDate || dataOutOfDate,
218+ canSkip: !noData && !schemaOutOfDate
219+ )
200220 }
201221
202- private func fetchNASRExpiration( ) throws -> Date ? {
203- let context = container. mainContext
222+ private static func fetchNASRExpiration( context: ModelContext ) throws -> Date ? {
204223 let nasrRawValue = CycleDataSource . nasr. rawValue
205224 var descriptor = FetchDescriptor < Cycle > (
206225 predicate: #Predicate { $0. _dataSource == nasrRawValue }
@@ -209,10 +228,9 @@ final class NavDataLoaderViewModel: WithIdentifiableError {
209228 return try context. fetch ( descriptor) . first? . expires
210229 }
211230
212- private func setAnyAirports( context: ModelContext ) throws {
213- var descriptor = FetchDescriptor < SF50_Shared . Airport > ( )
214- descriptor. fetchLimit = 1
215- noData = try context. fetch ( descriptor) . isEmpty
216- try recalculate ( )
231+ struct State {
232+ let noData : Bool
233+ let needsLoad : Bool
234+ let canSkip : Bool
217235 }
218236}
0 commit comments