diff --git a/KkuMulKum/Application/SceneDelegate.swift b/KkuMulKum/Application/SceneDelegate.swift index 1b3c8a38..8c666266 100644 --- a/KkuMulKum/Application/SceneDelegate.swift +++ b/KkuMulKum/Application/SceneDelegate.swift @@ -31,7 +31,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { DispatchQueue.main.async { if success { print("Auto login successful, showing main screen") - self?.showMainScreen() + self?.showLoginScreen() } else { print("Auto login failed, showing login screen") self?.showLoginScreen() diff --git a/KkuMulKum/Network/Service/AuthService.swift b/KkuMulKum/Network/Service/AuthService.swift index 10220178..39f475e9 100644 --- a/KkuMulKum/Network/Service/AuthService.swift +++ b/KkuMulKum/Network/Service/AuthService.swift @@ -13,7 +13,7 @@ protocol AuthServiceType { func getAccessToken() -> String? func getRefreshToken() -> String? func clearTokens() -> Bool - func performRequest(_ target: AuthTargetType, completion: @escaping (Result) -> Void) + func performRequest(_ target: AuthTargetType) async throws -> T } class AuthService: AuthServiceType { @@ -48,34 +48,34 @@ class AuthService: AuthServiceType { return keychainService.accessToken == nil && keychainService.refreshToken == nil } - func performRequest(_ target: AuthTargetType, completion: @escaping (Result) -> Void) { - provider.request(target) { result in - switch result { - case .success(let response): - print("서버 응답 상태 코드: \(response.statusCode)") - print("서버 응답 데이터: \(String(data: response.data, encoding: .utf8) ?? "디코딩 불가")") - - do { - let decodedResponse = try JSONDecoder().decode(ResponseBodyDTO.self, from: response.data) - if decodedResponse.success { - if let data = decodedResponse.data { - completion(.success(data)) - } else if T.self == EmptyModel.self { - completion(.success(EmptyModel() as! T)) - } else { - completion(.failure(.decodingError)) + func performRequest(_ target: AuthTargetType) async throws -> T { + return try await withCheckedThrowingContinuation { continuation in + provider.request(target) { result in + switch result { + case .success(let response): + print("서버 응답 상태 코드: \(response.statusCode)") + print("서버 응답 데이터: \(String(data: response.data, encoding: .utf8) ?? "디코딩 불가")") + + do { + let decodedResponse = try JSONDecoder().decode(ResponseBodyDTO.self, from: response.data) + guard decodedResponse.success else { + throw decodedResponse.error.map(self.mapErrorResponse) ?? NetworkError.unknownError("Unknown error occurred") } - } else if let error = decodedResponse.error { - completion(.failure(self.mapErrorResponse(error))) - } else { - completion(.failure(.unknownError("Unknown error occurred"))) + guard let data = decodedResponse.data else { + if T.self == EmptyModel.self { + continuation.resume(returning: EmptyModel() as! T) + } else { + throw NetworkError.decodingError + } + return + } + continuation.resume(returning: data) + } catch { + continuation.resume(throwing: error is NetworkError ? error : NetworkError.decodingError) } - } catch { - print("디코딩 오류: \(error)") - completion(.failure(.decodingError)) + case .failure(let error): + continuation.resume(throwing: NetworkError.networkError(error)) } - case .failure(let error): - completion(.failure(.networkError(error))) } } } diff --git a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift index 343a5782..cbbab194 100644 --- a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift @@ -238,6 +238,7 @@ class LoginViewModel: NSObject { } } } + private func clearTokensAndHandleError() { _ = authService.clearTokens() loginState.value = .notLogin diff --git a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift index 0c87385e..b98ce67b 100644 --- a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift +++ b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift @@ -10,7 +10,7 @@ import UIKit class LoginViewController: BaseViewController { private let loginView = LoginView() private let loginViewModel: LoginViewModel - + init(viewModel: LoginViewModel) { self.loginViewModel = viewModel super.init(nibName: nil, bundle: nil) @@ -48,44 +48,55 @@ class LoginViewController: BaseViewController { private func bindViewModel() { loginViewModel.loginState.bind(with: self) { owner, state in - switch state { - case .notLogin: - print("Login State: Not logged in") - case .login: - print("Login State: Logged in") - owner.navigateToMainScreen() - case .needOnboarding: - print("Login State: Need onboarding") - owner.navigateToOnboardingScreen() + + Task { + switch state { + case .notLogin: + print("Login State: Not logged in") + case .login: + print("Login State: Logged in") + await owner.navigateToMainScreen() + case .needOnboarding: + print("Login State: Need onboarding") + await owner.navigateToOnboardingScreen() + } } } loginViewModel.userName.bind(with: self) { owner, name in - if name != nil { - owner.navigateToMainScreen() - } else { - owner.navigateToOnboardingScreen() + Task { + if name != nil { + await owner.navigateToOnboardingScreen() + } else { + await owner.navigateToOnboardingScreen() + } } } loginViewModel.error.bind(with: self) { owner, error in - if !error.isEmpty { - print("Login Error: \(error)") - owner.showErrorAlert(message: error) + Task { + if !error.isEmpty { + print("Login Error: \(error)") + await owner.showErrorAlert(message: error) + } } } } - + @objc private func appleLoginTapped() { - loginViewModel.performAppleLogin(presentationAnchor: view.window!) + Task { + loginViewModel.performAppleLogin(presentationAnchor: view.window!) + } } @objc private func kakaoLoginTapped() { - loginViewModel.performKakaoLogin() + Task { + loginViewModel.performKakaoLogin() + } } - - private func navigateToMainScreen() { - DispatchQueue.main.async { + + private func navigateToMainScreen() async { + await MainActor.run { let mainTabBarController = MainTabBarController() let navigationController = UINavigationController(rootViewController: mainTabBarController) navigationController.isNavigationBarHidden = true @@ -95,8 +106,9 @@ class LoginViewController: BaseViewController { } } - private func navigateToOnboardingScreen() { - DispatchQueue.main.async { + private func navigateToOnboardingScreen() async { + await MainActor.run { + let nicknameViewController = NicknameViewController() if let navigationController = self.navigationController { navigationController.pushViewController(nicknameViewController, animated: true) @@ -109,10 +121,12 @@ class LoginViewController: BaseViewController { } } - private func showErrorAlert(message: String) { - print("Showing error alert with message: \(message)") - let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - present(alert, animated: true) + private func showErrorAlert(message: String) async { + await MainActor.run { + print("Showing error alert with message: \(message)") + let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } } } diff --git a/KkuMulKum/Source/Onboarding/Profile/VIewController/ProfileSetupViewController.swift b/KkuMulKum/Source/Onboarding/Profile/VIewController/ProfileSetupViewController.swift index d4debc42..c55a20f6 100644 --- a/KkuMulKum/Source/Onboarding/Profile/VIewController/ProfileSetupViewController.swift +++ b/KkuMulKum/Source/Onboarding/Profile/VIewController/ProfileSetupViewController.swift @@ -50,18 +50,19 @@ class ProfileSetupViewController: BaseViewController { } @objc private func confirmButtonTapped() { - viewModel.uploadProfileImage { [weak self] success in - if success { - DispatchQueue.main.async { - let welcomeVC = WelcomeViewController( - viewModel: WelcomeViewModel(nickname: self?.viewModel.nickname ?? "") - ) - welcomeVC.modalPresentationStyle = .fullScreen - self?.present(welcomeVC, animated: true, completion: nil) - } - } - } - } + Task { + let success = await viewModel.uploadProfileImage() + if success { + DispatchQueue.main.async { + let welcomeVC = WelcomeViewController( + viewModel: WelcomeViewModel(nickname: self.viewModel.nickname) + ) + welcomeVC.modalPresentationStyle = .fullScreen + self.present(welcomeVC, animated: true, completion: nil) + } + } + } + } @objc private func skipButtonTapped() { let welcomeVC = WelcomeViewController( diff --git a/KkuMulKum/Source/Onboarding/Profile/ViewModel/ProfileSetupViewModel.swift b/KkuMulKum/Source/Onboarding/Profile/ViewModel/ProfileSetupViewModel.swift index cc2c083c..899c47bb 100644 --- a/KkuMulKum/Source/Onboarding/Profile/ViewModel/ProfileSetupViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Profile/ViewModel/ProfileSetupViewModel.swift @@ -32,39 +32,35 @@ class ProfileSetupViewModel { isConfirmButtonEnabled.value = imageData != nil } - func uploadProfileImage(completion: @escaping (Bool) -> Void) { - print("uploadProfileImage 함수 호출됨") - guard let imageData = imageData else { - print("이미지 데이터가 없습니다.") - serverResponse.value = "이미지 데이터가 없습니다." - completion(false) - return - } - - print("업로드할 이미지 데이터 크기: \(imageData.count) bytes") - - let fileName = "profile_image.jpg" - let mimeType = "image/jpeg" - - authService.performRequest( - .updateProfileImage( - image: imageData, - fileName: fileName, - mimeType: mimeType - ) - ) { [weak self] (result: Result) in - print("네트워크 요청 완료") - switch result { - case .success(_): - self?.serverResponse.value = "프로필 이미지가 성공적으로 업로드되었습니다." - print("프로필 이미지 업로드 성공") - completion(true) - case .failure(let error): - self?.handleError(error) - completion(false) - } - } - } + func uploadProfileImage() async -> Bool { + print("uploadProfileImage 함수 호출됨") + guard let imageData = imageData else { + print("이미지 데이터가 없습니다.") + serverResponse.value = "이미지 데이터가 없습니다." + return false + } + + print("업로드할 이미지 데이터 크기: \(imageData.count) bytes") + + let fileName = "profile_image.jpg" + let mimeType = "image/jpeg" + + do { + let _: EmptyModel = try await authService.performRequest( + .updateProfileImage( + image: imageData, + fileName: fileName, + mimeType: mimeType + ) + ) + serverResponse.value = "프로필 이미지가 성공적으로 업로드되었습니다." + print("프로필 이미지 업로드 성공") + return true + } catch { + handleError(error as? NetworkError ?? .unknownError("알 수 없는 오류가 발생했습니다.")) + return false + } + } private func handleError(_ error: NetworkError) { serverResponse.value = error.message