fix: 22 audit fixes — concurrency, memory, performance, accessibility
- Move 7 Data(contentsOf:) calls off MainActor via Task.detached (BootstrapService) - Batch-fetch N+1 queries in sync merge loops (CanonicalSyncService) - Predicate-based gamesForTeam fetch instead of fetching all games (DataProvider) - Proper Sendable on RouteInfo with nonisolated(unsafe) polyline (LocationService) - [weak self] in BGTaskScheduler register closures (BackgroundSyncManager) - Cache tripDays, routeWaypoints as @State with recompute (TripDetailView) - Remove unused AnyCancellable, add Task lifecycle management (TripDetailView) - Cache sportStadiums, recentVisits as stored properties (ProgressViewModel) - Dynamic Type fonts replacing hardcoded sizes (OnboardingPaywallView) - Accessibility labels/hints on stadium picker, date picker, map, stats, settings toggle, and day cards Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -202,12 +202,13 @@ final class BootstrapService {
|
||||
throw BootstrapError.bundledResourceNotFound("stadiums_canonical.json")
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let stadiums: [JSONCanonicalStadium]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
stadiums = try JSONDecoder().decode([JSONCanonicalStadium].self, from: data)
|
||||
stadiums = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONCanonicalStadium].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("stadiums_canonical.json", error)
|
||||
}
|
||||
@@ -238,12 +239,13 @@ final class BootstrapService {
|
||||
return
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let aliases: [JSONStadiumAlias]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
aliases = try JSONDecoder().decode([JSONStadiumAlias].self, from: data)
|
||||
aliases = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONStadiumAlias].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("stadium_aliases.json", error)
|
||||
}
|
||||
@@ -280,12 +282,13 @@ final class BootstrapService {
|
||||
return
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let structures: [JSONLeagueStructure]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
structures = try JSONDecoder().decode([JSONLeagueStructure].self, from: data)
|
||||
structures = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONLeagueStructure].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("league_structure.json", error)
|
||||
}
|
||||
@@ -319,12 +322,13 @@ final class BootstrapService {
|
||||
throw BootstrapError.bundledResourceNotFound("teams_canonical.json")
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let teams: [JSONCanonicalTeam]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
teams = try JSONDecoder().decode([JSONCanonicalTeam].self, from: data)
|
||||
teams = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONCanonicalTeam].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("teams_canonical.json", error)
|
||||
}
|
||||
@@ -352,12 +356,13 @@ final class BootstrapService {
|
||||
return
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let aliases: [JSONTeamAlias]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
aliases = try JSONDecoder().decode([JSONTeamAlias].self, from: data)
|
||||
aliases = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONTeamAlias].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("team_aliases.json", error)
|
||||
}
|
||||
@@ -393,12 +398,13 @@ final class BootstrapService {
|
||||
throw BootstrapError.bundledResourceNotFound("games_canonical.json")
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let games: [JSONCanonicalGame]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
games = try JSONDecoder().decode([JSONCanonicalGame].self, from: data)
|
||||
games = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONCanonicalGame].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("games_canonical.json", error)
|
||||
}
|
||||
@@ -462,12 +468,13 @@ final class BootstrapService {
|
||||
return
|
||||
}
|
||||
|
||||
let data: Data
|
||||
let sports: [JSONCanonicalSport]
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
sports = try JSONDecoder().decode([JSONCanonicalSport].self, from: data)
|
||||
sports = try await Task.detached {
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode([JSONCanonicalSport].self, from: data)
|
||||
}.value
|
||||
} catch {
|
||||
throw BootstrapError.jsonDecodingFailed("sports_canonical.json", error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user