From 29facff005b0efa39ab4112e9e02e23bbc6b4fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8B=9C=EC=9A=B0?= <266720604+dltldn1234@users.noreply.github.com> Date: Thu, 5 Nov 2026 20:23:00 +0900 Subject: [PATCH] perf: [#395] parallelize home startup data --- heatguard-iOS/App/HeatGuardApp.swift | 8 +++++++- .../Core/Auth/HGAuthenticationService.swift | 12 +++++++++--- .../Presentation/Features/Home/HomeView.swift | 13 ++++++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/heatguard-iOS/App/HeatGuardApp.swift b/heatguard-iOS/App/HeatGuardApp.swift index ff0b13f..5bf849c 100644 --- a/heatguard-iOS/App/HeatGuardApp.swift +++ b/heatguard-iOS/App/HeatGuardApp.swift @@ -15,6 +15,7 @@ struct HeatGuardApp: App { @State private var showsTeamFlow = false @State private var startsAccountRegistration = false @State private var pendingInvitationToken: String? + @State private var restoredProfile: HGTeamProfile? var body: some Scene { WindowGroup { @@ -46,6 +47,7 @@ struct HeatGuardApp: App { } } else if isAuthenticated { HomeView( + initialProfile: restoredProfile, onSessionEnded: handleSessionEnded, onTeamSelectionRequested: { showsTeamFlow = true } ) @@ -77,7 +79,9 @@ struct HeatGuardApp: App { try? HGAuthTokenStore(account: "app-session-access-token").clear() UserDefaults.standard.removeObject(forKey: "selected-app-site-id") do { - isAuthenticated = (try await HGAuthenticationService().restoreSession()) != nil + let session = try await HGAuthenticationService().restoreSession() + restoredProfile = session?.profile + isAuthenticated = session != nil if isAuthenticated { await routeToSelectedTeamIfNeeded() } } catch { isAuthenticated = false @@ -87,6 +91,7 @@ struct HeatGuardApp: App { @MainActor private func routeAuthenticatedSession() async { + restoredProfile = nil isAuthenticated = true await routeToSelectedTeamIfNeeded() } @@ -133,6 +138,7 @@ struct HeatGuardApp: App { @MainActor private func handleSessionEnded() { HGAuthenticationService().endLocalSession() + restoredProfile = nil isAuthenticated = false showsTeamFlow = false } diff --git a/heatguard-iOS/Core/Auth/HGAuthenticationService.swift b/heatguard-iOS/Core/Auth/HGAuthenticationService.swift index f4309f1..0b9e120 100644 --- a/heatguard-iOS/Core/Auth/HGAuthenticationService.swift +++ b/heatguard-iOS/Core/Auth/HGAuthenticationService.swift @@ -111,8 +111,8 @@ struct HGAuthenticationService { return nil } - _ = try await currentProfile() - return TeamSession() + let profile = try await currentProfile() + return TeamSession(profile: profile) } func currentProfile() async throws -> HGTeamProfile { @@ -327,7 +327,13 @@ private struct PasswordChangeResponse: Decodable { private struct WithdrawalRequest: Encodable { let currentPassword: String; let reason: String? } -struct TeamSession: Equatable {} +struct TeamSession: Equatable { + let profile: HGTeamProfile? + + init(profile: HGTeamProfile? = nil) { + self.profile = profile + } +} struct HGLoginCredentials: Codable { let email: String diff --git a/heatguard-iOS/Presentation/Features/Home/HomeView.swift b/heatguard-iOS/Presentation/Features/Home/HomeView.swift index 42c4156..310d98e 100644 --- a/heatguard-iOS/Presentation/Features/Home/HomeView.swift +++ b/heatguard-iOS/Presentation/Features/Home/HomeView.swift @@ -8,6 +8,7 @@ struct HomeView: View { init( initialDashboard: HomeDashboard? = nil, + initialProfile: HGTeamProfile? = nil, onSessionEnded: @escaping () -> Void = {}, onTeamSelectionRequested: @escaping () -> Void = {} ) { @@ -15,6 +16,7 @@ struct HomeView: View { self.onTeamSelectionRequested = onTeamSelectionRequested self.loadsRemoteData = initialDashboard == nil _dashboard = State(initialValue: initialDashboard ?? .unavailable) + _teamProfile = State(initialValue: initialProfile) _checklist = State(initialValue: initialDashboard?.checklist ?? HGChecklistSummary(times: [], checkedCount: nil, totalCount: nil)) _unreadNotificationCount = State(initialValue: initialDashboard?.unreadNotificationCount ?? 0) } @@ -161,10 +163,15 @@ struct HomeView: View { .navigationDestination(for: HomeFlowRoute.self, destination: destinationView) .task { guard loadsRemoteData else { return } - await loadDashboard() - await loadProfile() - await restoreCurrentEmergencyCall() loadStoredDraft() + async let dashboardLoad: Void = loadDashboard() + async let emergencyLoad: Void = restoreCurrentEmergencyCall() + if teamProfile == nil { + async let profileLoad: Void = loadProfile() + _ = await (dashboardLoad, profileLoad, emergencyLoad) + } else { + _ = await (dashboardLoad, emergencyLoad) + } } .alert("홈 데이터를 불러오지 못했습니다.", isPresented: dashboardErrorAlert) { Button("다시 시도") {