https://explorer89.tistory.com/360
🔥 Firebase의 회원가입 (이메일&비밀번호 / 소셜로그인)
// ✅ 소셜 로그인 (Facebook, Google, Apple 등)func signIn(with credential: AuthCredential) -> AnyPublisher { return Future { promise in Auth.auth().signIn(with: credential) { authResult, error in if let error = error { promise(.failure(error)) //
explorer89.tistory.com
✅ 1. AuthenticationService (Firebase 연동)
우선, Firebase Authentication을 처리할 AuthenticationService 클래스를 만든다.
이 클래스는 Firebase API를 Combine을 이용해서 Publisher로 변환하는 역할을 한다.
import FirebaseAuth
import Combine
final class AuthenticationService {
static let shared = AuthenticationService()
private init() {}
/// 📌 이메일과 비밀번호로 회원가입
func registerUser(email: String, password: String) -> AnyPublisher<User, Error> {
return Future { promise in
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let error = error {
promise(.failure(error)) // ❌ 실패 시 에러 반환
} else if let user = authResult?.user {
promise(.success(user)) // ✅ 성공 시 User 반환
}
}
}
.eraseToAnyPublisher()
}
/// 📌 소셜 로그인 (Google, Apple 등)
func signIn(with credential: AuthCredential) -> AnyPublisher<User, Error> {
return Future { promise in
Auth.auth().signIn(with: credential) { authResult, error in
if let error = error {
promise(.failure(error)) // ❌ 실패 시 에러 반환
} else if let user = authResult?.user {
promise(.success(user)) // ✅ 성공 시 User 반환
}
}
}
.eraseToAnyPublisher()
}
}
✅ 2. AuthViewModel (비즈니스 로직 & 상태 관리)
AuthenticationService를 사용해서 회원가입과 로그인을 처리하는 AuthViewModel을 만든다.
@Published를 이용해 UI가 자동으로 업데이트되도록 한다.
import Combine
import FirebaseAuth
final class AuthViewModel: ObservableObject {
@Published var user: User? = nil // 현재 로그인한 사용자 정보
@Published var errorMessage: String? = nil // 에러 메시지
private var cancellables = Set<AnyCancellable>()
/// 📌 이메일 회원가입
func register(email: String, password: String) {
AuthenticationService.shared.registerUser(email: email, password: password)
.receive(on: DispatchQueue.main) // UI 업데이트는 메인 스레드에서
.sink { completion in
switch completion {
case .failure(let error):
self.errorMessage = "회원가입 실패: \(error.localizedDescription)"
case .finished:
print("✅ 회원가입 성공!")
}
} receiveValue: { user in
self.user = user
}
.store(in: &cancellables)
}
/// 📌 소셜 로그인
func signInWithCredential(_ credential: AuthCredential) {
AuthenticationService.shared.signIn(with: credential)
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
case .failure(let error):
self.errorMessage = "로그인 실패: \(error.localizedDescription)"
case .finished:
print("✅ 소셜 로그인 성공!")
}
} receiveValue: { user in
self.user = user
}
.store(in: &cancellables)
}
}
🔥 MVVM + Combine에서 enum을 사용한 로그인/회원가입 통합 처리
✅ 1. AuthMethod (인증 방식 구분)
import FirebaseAuth
/// 로그인 / 회원가입 방식을 구분하는 enum
enum AuthMethod {
case email(email: String, password: String) // 이메일 회원가입/로그인
case social(credential: AuthCredential) // 소셜 로그인 (Google, Apple 등)
}
✅ 2. AuthenticationService (Firebase 연동)
Firebase 인증 API를 Combine과 함께 사용하여, AuthMethod를 활용한 단일 메서드로 로그인 & 회원가입을 통합 처리한다.
import FirebaseAuth
import Combine
final class AuthenticationService {
static let shared = AuthenticationService()
private init() {}
/// `AuthMethod`를 이용해 이메일 또는 소셜 로그인 처리
func signInOrRegister(using method: AuthMethod) -> AnyPublisher<User, Error> {
switch method {
case .email(let email, let password):
return registerUser(with: email, password: password)
case .social(let credential):
return signIn(with: credential)
}
}
/// 이메일 & 비밀번호 회원가입
private func registerUser(with email: String, password: String) -> AnyPublisher<User, Error> {
return Future { promise in
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let error = error {
promise(.failure(error)) // ❌ 실패 시 에러 반환
} else if let user = authResult?.user {
promise(.success(user)) // ✅ 성공 시 User 반환
}
}
}
.eraseToAnyPublisher()
}
/// 소셜 로그인 (Google, Apple 등)
private func signIn(with credential: AuthCredential) -> AnyPublisher<User, Error> {
return Future { promise in
Auth.auth().signIn(with: credential) { authResult, error in
if let error = error {
promise(.failure(error)) // ❌ 실패 시 에러 반환
} else if let user = authResult?.user {
promise(.success(user)) // ✅ 성공 시 User 반환
}
}
}
.eraseToAnyPublisher()
}
}
✅ 3. AuthViewModel (비즈니스 로직 & 상태 관리)
AuthMethod를 사용해서 signInOrRegister(using:) 메서드를 호출한다.
import Combine
import FirebaseAuth
final class AuthViewModel: ObservableObject {
@Published var user: User? = nil // 현재 로그인한 사용자 정보
@Published var errorMessage: String? = nil // 에러 메시지
private var cancellables = Set<AnyCancellable>()
/// `AuthMethod`를 사용한 로그인 / 회원가입 처리
func authenticate(using method: AuthMethod) {
AuthenticationService.shared.signInOrRegister(using: method)
.receive(on: DispatchQueue.main) // UI 업데이트는 메인 스레드에서
.sink { completion in
switch completion {
case .failure(let error):
self.errorMessage = "❌ 로그인/회원가입 실패: \(error.localizedDescription)"
case .finished:
print("✅ 로그인/회원가입 성공!")
}
} receiveValue: { user in
self.user = user
}
.store(in: &cancellables)
}
}
'UIKIT > Firebase' 카테고리의 다른 글
❓ FireStore 내에 회원정보를 불러오는 데 왜 tryMap? (0) | 2025.02.27 |
---|---|
❓ Firebase 로그인 메서드 내 map의 역할 (0) | 2025.02.27 |
🚀 Future를 사용한 방식 vs map(\.user)을 사용한 방식의 차이점 (Future 는 필수인가?) (0) | 2025.02.26 |
🤔 소셜 미디어 로그인 방법에서 Future를 사용한 이유? (0) | 2025.02.26 |
🔥 Firebase의 회원가입 (이메일&비밀번호 / 소셜로그인) (0) | 2025.02.26 |