본문 바로가기

Project/MovieClip

👤 Firebase에 로그인, 회원정보를 FireStore 저장, 회원정보 불러오기

✅ 로그인 기능 구현 

/// 이메일과 비밀번호로 로그인하는 함수
func loginUser(email: String, password: String) -> AnyPublisher<User, Error> {
    return Auth.auth().signIn(withEmail: email, password: password)
        .map(\.user)         // ✅ authResult?.user 만 추출 
        .eraseToAnyPublisher()
}

✅ 특징

✔️ signIn(withEmail:password:)는 원래 Future 형태로 제공됨 → 따로 감쌀 필요 없음
✔️ map(\.user)를 사용해 authResult?.user만 반환하여 더 간결한 코드
✔️ .eraseToAnyPublisher()로 반환 타입을 AnyPublisher<User, Error>로 변환

https://explorer89.tistory.com/368

 

❓ Firebase 로그인 메서드 내 map의 역할

✅ map(\.user)의 역할func loginUser(with email: String, password: String) -> AnyPublisher { return Auth.auth().signIn(withEmail: email, password: password) .map(\.user) // ✅ 여기서 map이 동작 .eraseToAnyPublisher()} 🔹 Firebase의 signIn(wit

explorer89.tistory.com

 

 

✅ 회원정보를 FireStore 저장

class DatabaseManager {
    
    // MARK: - Variable
    static let shared = DatabaseManager()
    
    let db = Firestore.firestore()
    let userPath: String = "users"
    
    // MARK: - Function
    /// ✅ 회원정보를 fireStore에 저장하는 메서드
    func collectionUsers(add user: User) -> AnyPublisher<Bool, Error> {
        let movieClipUser = MovieClipUser(from: user)
        return db.collection(userPath)
            .document(movieClipUser.id)
            .setData(from: movieClipUser) // ✅ 여기까지, firebase FireStore의 특정 문서에 데이터를 저장하는 비동기 작업
            .map { _ in return true }     // ✅ Firebase에 데이터를 저장한 후, 성공적으로 완료되었음을 나타내는 true 값을 반환
            .eraseToAnyPublisher()        // ✅ 타입을 AnyPublisher<Bool, Error>로 변환하여 외부에서 사용하기 쉽게 만듦
    }
    ...

 

final class AuthenticationViewModel: ObservableObject {
	...
    /// ✅ 회원 정보를 firebase FireStore의 특정 문서에 저장하는 메서드
    func createRecord(for user: User) {
        DatabaseManager.shared.collectionUsers(add: user)
            .sink { [weak self] completion in
                switch completion {
                case .failure(let error):
                    self?.error = error.localizedDescription
                case .finished:
                    print("회원 정보 저장 성공")
                }
            } receiveValue: { state in
                print("Adding user record to database: \(state)")
            }
            .store(in: &cancelable)
    }
}

 

 FireStore에 저장한 회원정보 불러오기

class DatabaseManager {
    
    ...
    
    /// 회원정보를 반환하는 메서드
    func collectionUsers(retrieve id: String) -> AnyPublisher<MovieClipUser, Error> {
        db.collection(userPath)
            .document(id)
            .getDocument()                                        // ✅ 여기까지 Firestore에서 특정 문서를 가져오는 비동기 작업
            .tryMap { try $0.data(as: MovieClipUser.self) }       // ✅ DocumentSnapshot을 MovieClipUser 모델로 변환, 변환 실패하면 tryMap이 자동으로 에러를 throw (map은 단순 변환만 가능, 에러 throw 불가능)
            .eraseToAnyPublisher()
    }
    
}

 

✅ FireStore 내에 회원정보를 불러오는 데 왜 tryMap?

https://explorer89.tistory.com/370

 

 

class HomViewController: UIViewController {
	...
    
    private func bindView() {
        // ✅ 회원정보 가져오기 
        viewModel.retrieveUser()
		
        // ✅ 회원정보가 작성되지 않았다면 ➡️ ProfileDataFormViewController 이동
        viewModel.$user
            .sink { [weak self] user in
                guard let user = user else { return }
                if !user.isUserOnboarded {
                    self?.completeUserOnboarding()
                }
            }
            .store(in: &cancelable)
    }

    func completeUserOnboarding() {
        let profileDataFormVC = ProfileDataFormViewController()
        present(profileDataFormVC, animated: true)
    }

 

 

 

📌 회원 가입에서 프로필 작성까지 순서 

회원가입 ➡️ 회원정보 저장 ➡️ 회원정보 불러오기 ➡️ 프로필 작성 창 띄우기