본문 바로가기

UIKIT/Firebase

🚀 Future를 사용한 방식 vs map(\.user)을 사용한 방식의 차이점 (Future 는 필수인가?)

두 방식 모두 Firebase의 createUser(withEmail:password:)를 Combine을 활용하여 AnyPublisher<User, Error> 형태로 변환하지만, 비동기 처리 방식이 조금 다릅니다. 

 

 

✅ 1. Future를 사용한 방식

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()
}

 

🔹 동작 방식

  1. Future는 내부에서 Firebase createUser(withEmail:password:)를 호출
  2. Firebase가 비동기적으로 응답을 반환
  3. 성공하면 promise(.success(user)), 실패하면 promise(.failure(error)) 호출
  4. Future는 값을 한 번만 방출하고 자동으로 종료됨

✅ 장점

✔️ Future를 사용하면 Firebase의 콜백 기반 API를 Combine 스트림으로 변환 가능
✔️ 한 번만 값이 방출됨 (네트워크 요청 후 완료되면 끝)
✔️ Combine과 함께 체이닝해서 .map(), .flatMap() 등과 연동 가능

❌ 단점

⚠️ Future를 사용하면 내부적으로 콜백을 직접 감싸야 하므로 코드가 다소 길어짐
⚠️ Firebase의 기존 Combine 지원 API를 활용하지 않고 직접 감싸는 방식이라 불필요할 수 있음

 

✅ 2. map(\.user)을 사용한 방식 (Firebase Combine API 활용)

func registerUser(with email: String, password: String) -> AnyPublisher<User, Error> {
    return Auth.auth().createUser(withEmail: email, password: password)
        .map(\.user) // authResult에서 user 객체만 추출
        .eraseToAnyPublisher()
}

 

🔹 동작 방식

  1. Firebase의 createUser(withEmail:password:)는 Completion Handler 기반 API지만,
    Swift의 Combine 확장 덕분에 자동으로 Publisher로 변환됨
  2. map(\.user)를 사용하여 authResult에서 user만 추출
  3. eraseToAnyPublisher()를 사용하여 반환 타입을 통일

✅ 장점

✔️ 코드가 더 간결함 → Firebase가 Publisher를 자동으로 제공하기 때문에 직접 감쌀 필요 없음
✔️ Swift의 Combine 지원 API를 활용하여 효율적인 코드 작성 가능
✔️ 불필요한 콜백을 제거하고 바로 체이닝 가능

❌ 단점

⚠️ Firebase가 Combine을 지원하지 않는 경우에는 사용할 수 없음
⚠️ Future처럼 명확하게 성공/실패 처리를 직접 컨트롤할 수 없음

 

 

🚀 Future를 사용하면 회원가입 성공/실패 이벤트를 추가할 수 있을까?

 Future를 사용하면 회원가입(또는 로그인)의 성공/실패에 따른 이벤트를 추가하는 것이 가능!

하지만 Future 없이도 Firebase의 Combine 지원 API를 사용하면 가능!
즉, Future는 필수는 아니지만, 상황에 따라 필요할 수도 있음!

 

✅ 1. Future를 사용하면 회원가입 성공/실패 이벤트를 직접 추가 가능

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 {
                print("❌ 회원가입 실패! \(error.localizedDescription)")
                // 🚀 실패 이벤트 추가 가능
                Analytics.logEvent("signup_failed", parameters: ["reason": error.localizedDescription])
                promise(.failure(error))  // 실패 처리
            } else if let user = authResult?.user {
                print("✅ 회원가입 성공! \(user.email ?? "Unknown")")
                // 🚀 성공 이벤트 추가 가능
                Analytics.logEvent("signup_success", parameters: ["email": user.email ?? ""])
                promise(.success(user))   // 성공 처리
            }
        }
    }
    .eraseToAnyPublisher()
}

 

✅ Future를 사용하면 이런 장점이 있음!

✔️ 성공 이벤트를 추가할 수 있음 (예: Firebase Analytics에 "signup_success" 로그 저장)
✔️ 실패 이벤트를 추가할 수 있음 (예: 실패 원인을 로그로 남기기)
✔️ 콜백 내부에서 명확하게 성공/실패를 컨트롤 가능

 

 

✅ 2. Future 없이 Combine 지원 API를 사용해도 가능!

func registerUser(with email: String, password: String) -> AnyPublisher<User, Error> {
    return Auth.auth().createUser(withEmail: email, password: password)
        .handleEvents(receiveOutput: { authResult in
            print("✅ 회원가입 성공! \(authResult.user.email ?? "Unknown")")
            // 🚀 성공 이벤트 추가 가능
            Analytics.logEvent("signup_success", parameters: ["email": authResult.user.email ?? ""])
        }, receiveCompletion: { completion in
            if case .failure(let error) = completion {
                print("❌ 회원가입 실패! \(error.localizedDescription)")
                // 🚀 실패 이벤트 추가 가능
                Analytics.logEvent("signup_failed", parameters: ["reason": error.localizedDescription])
            }
        })
        .map(\.user)
        .eraseToAnyPublisher()
}

 

✅ Future 없이도 이벤트 추가 가능!

✔️ handleEvents()를 사용하면 Future 없이도 성공/실패 시 이벤트 추가 가능
✔️ Firebase의 Combine 지원 API를 그대로 활용하여 코드를 간결하게 유지 가능
✔️ .map(\.user)을 사용하여 authResult에서 user만 추출

 

 

💡 즉, Future를 사용하지 않아도 handleEvents()를 활용하면 회원가입 성공/실패 이벤트를 추가할 수 있어!

🚀 Future는 Firebase가 Combine을 지원하지 않는 API에서만 필요할 뿐, 필수는 아니야! ✅