본문 바로가기

Project/FirebaseTest

FireBase - 사용자 등록 기능

https://firebase.google.com/docs/auth/ios/start?hl=ko&_gl=1*18o4hk5*_up*MQ..*_ga*NTI2ODUyODA1LjE3MzMxOTIwNjM.*_ga_CW55HF8NVT*MTczMzE5MjA2My4xLjAuMTczMzE5MjA2My4wLjAuMA..

 

Apple 플랫폼에서 Firebase 인증 시작하기  |  Firebase Authentication

2024년 데모 데이에서 Firebase를 사용하여 AI 기반 앱을 빌드하고 실행하는 방법에 관한 데모를 시청하세요. 지금 시청하세요. 의견 보내기 Apple 플랫폼에서 Firebase 인증 시작하기 컬렉션을 사용해

firebase.google.com

 

https://normalblog.tistory.com/6

 

[Firebase] IOS 프로젝트에 Firebase 추가

IOS프로젝트에 Firebase 추가하기 Firebase 프로젝트 생성은 하기 링크의 이전 글을 참고 2022.02.03 - [Develop/Firebase] - [Firebase] Firebase 프로젝트 생성 [Firebase] Firebase 프로젝트 생성 Firebase 프로젝트 생성하

normalblog.tistory.com

 

AuthService

import Foundation
import FirebaseAuth
import FirebaseFirestore

class AutheService {
    
    public static let shared = AutheService()
    private init() { }
    
    
    /// A method to register the user
    /// - Parameters:
    ///   - userRequest: The users information (email, password, username)
    ///   - completion: A completion with two values...
    ///   - Bool: wasRegistered - Determines if the user was registered and saved in the database correctly
    ///   - Error?: An optional error if firebase provides once
    public func registerUser(with userRequest: RegisterUserRequest,
                             completion: @escaping (Bool, Error?) -> Void) {
        
        let username = userRequest.username
        let email = userRequest.email
        let password = userRequest.password
        
        Auth.auth().createUser(withEmail: email, password: password) { result, error in
            if let error = error {
                completion(false, error)
                return
            }
            
            guard let resultUser = result?.user else {
                completion(false, nil)
                return
            }
            
            let db = Firestore.firestore()
            
            db.collection("users")
                .document(resultUser.uid)
                .setData([
                    "username": username,
                    "email": email
                ]) { error in
                    if let error = error {
                        completion(false, error)
                        return
                    }
                    
                    completion(true, nil)
                }
        }
    }
    
}

 

위의 코드는 AuthService라는 이름의 클래스를 정의하고, Firebase Authentication과 Firestore를 활용하여 사용자 등록(회원가입) 기능을 구현한 것입니다. 이 클래스는 앱에서 사용자 인증과 관련된 기능을 간편하게 처리하도록 설계되었습니다.

 

1. 주요 구성 요소 설명

1.1 클래스 선언 및 싱글턴 패턴

public static let shared = AutheService()
private init() { }

 

 

  • shared:
    • 클래스의 유일한 인스턴스를 정의한 싱글턴(Singleton) 패턴.
    • 이를 통해 여러 곳에서 하나의 AuthService 객체를 공유할 수 있습니다.
  • private init():
    • 외부에서 새로운 인스턴스를 생성하지 못하도록 생성자를 private로 설정.
    • 클래스의 인스턴스를 단 하나로 제한하여 리소스를 절약하고, 전역적으로 사용할 수 있도록 설계.

 

1.2 사용자 등록 메서드

public func registerUser(with userRequest: RegisterUserRequest, completion: @escaping (Bool, Error?) -> Void)

 

 

매개변수

  • userRequest:
    • 사용자 정보를 포함하는 구조체(RegisterUserRequest).
    • 예: 이메일, 비밀번호, 사용자 이름 등이 포함.
  • completion:
    • 비동기 작업의 결과를 반환하기 위한 클로저.
    • 클로저 형태: (Bool, Error?) -> Void.
      • Bool: 사용자 등록 성공 여부.
      • Error?: Firebase에서 발생한 오류 정보.

🔥 왜 completion을 사용했는가? 🔥

1.1 비동기 작업 처리

  • registerUser 메서드는 Firebase Authentication과 Firestore와 통신하며, 이 작업은 비동기적으로 수행됩니다.
    • 비동기 작업은 완료되기까지 시간이 걸리며, 결과를 즉시 반환하지 않습니다.
    • 예: Firebase에서 사용자를 등록하고, Firestore에 데이터를 저장하는 데 걸리는 시간은 네트워크 상태에 따라 달라집니다.
  • completion 클로저를 사용하면 비동기 작업이 완료된 후, 결과를 호출한 코드로 비동기적으로 전달할 수 있습니다.

1.2 작업 완료 상태 전달

  • completion을 통해 작업의 성공 여부에러 정보를 호출한 측에 전달합니다.
  • 예를 들어:
    • 성공적으로 사용자 등록과 데이터 저장이 완료되었는지 호출한 코드에서 알 수 있음.
    • 실패 시 Firebase가 제공하는 Error 객체를 반환하여, 어떤 문제가 발생했는지 파악할 수 있음.

1.3 호출한 측에서 후속 작업 처리

  • completion을 사용하면 메서드를 호출한 곳에서 작업 완료 후 어떤 작업을 할지를 정의할 수 있습니다.
    • 예: 사용자 등록 성공 후 다음 화면으로 이동.
    • 예: 사용자 등록 실패 시 경고창 표시.

 

2. completion의 클로저 형태

completion: @escaping (Bool, Error?) -> Void

 

이 클로저의 형태를 분해해서 설명하겠습니다:

2.1 (Bool, Error?)

  • 클로저의 매개변수로 작업 결과를 반환.
    • Bool: 작업이 성공했는지(true) 실패했는지(false)를 나타냅니다.
    • Error?: Firebase에서 발생한 오류 객체를 전달합니다. 오류가 없으면 nil이 반환됩니다.

2.2 -> Void

  • 클로저의 반환값이 Void(즉, 아무 값도 반환하지 않음)를 나타냅니다.
  • 클로저 내부에서는 작업 결과를 사용하거나 다른 동작을 수행하지만, 클로저 자체는 호출한 곳에 어떤 값을 반환하지 않습니다.

 

3. 예제와 흐름

사용자 등록 호출

let userRequest = RegisterUserRequest(username: "JohnDoe", email: "johndoe@example.com", password: "password123")

AutheService.shared.registerUser(with: userRequest) { wasRegistered, error in
    if wasRegistered {
        print("User registered successfully.")
        // 예: 다음 화면으로 이동
    } else if let error = error {
        print("Registration failed: \(error.localizedDescription)")
        // 예: 경고창 표시
    }
}

 

  • registerUser 호출:
    • userRequest로 사용자 정보를 전달.
    • completion 클로저에서 성공 여부(wasRegistered)와 오류 정보(error)를 받아 후속 작업 수행.

비동기 처리 흐름

  1. registerUser가 호출되고 Firebase에서 사용자 생성 작업 시작.
  2. Firebase 작업이 완료되면 결과를 completion으로 호출자에게 반환.
  3. 호출자는 completion을 통해 성공 여부와 오류에 따라 적절한 동작 수행.

 

4. 비동기 작업에서 completion이 중요한 이유

4.1 비동기 작업의 본질

  • 비동기 작업은 완료되기 전까지 실행 흐름을 차단하지 않습니다. 즉, 아래의 코드가 먼저 실행될 수 있습니다.
  • completion은 비동기 작업이 완료된 시점에 호출되므로, 호출자는 정확한 결과를 알 수 있습니다.

4.2 작업 결과 전달

  • 네트워크 요청 결과를 즉각 반환하는 것은 불가능하므로, 클로저(completion)를 통해 작업이 끝났을 때 결과를 전달하는 방식이 일반적입니다.

 

completion에서 (Bool, Error?) -> Void의 의미

  • 클로저의 정의인 (Bool, Error?) -> Void는:
    • 클로저 자체의 반환값이 없다는 것을 의미합니다. (-> Void)
    • 하지만, 클로저를 호출할 때 매개변수로 데이터를 전달할 수 있다는 것을 나타냅니다. ((Bool, Error?))
  • 클로저 자체는 호출한 쪽에 값을 반환하지 않음.
  • 대신, 클로저를 호출하는 쪽에서 Bool과 Error? 값을 클로저 내부로 전달해 줄 수 있습니다.

 

비유를 통해 이해하기

클로저를 메시지를 전달하는 수단으로 생각해보세요.

  • 클로저는 일방적인 메시지 전달만 할 뿐, 메시지를 반환하지 않습니다.
  • 예:
    • 내가 **편지(클로저)**에 내용을 적어 누군가에게 전달하지만, 편지 자체는 나에게 아무것도 반환하지 않음.
    • 하지만 편지에 적힌 내용(매개변수)은 상대방에게 전달되어 해석될 수 있음.

1.3 메서드 동작

Firebase Authentication - 사용자 등록

Auth.auth().createUser(withEmail: email, password: password) { result, error in
    if let error = error {
        completion(false, error)
        return
    }
    
    guard let resultUser = result?.user else {
        completion(false, nil)
        return
    }
    ...
}

 

  • Auth.auth().createUser:
    • Firebase Authentication을 사용하여 새 사용자를 등록.
    • 매개변수:
      • email: 사용자의 이메일.
      • password: 사용자의 비밀번호.
    • 완료 핸들러:
      • result: 성공적으로 생성된 사용자 정보를 포함.
      • error: 등록 실패 시 발생한 오류.
  • 에러 처리:
    • 오류가 발생하면 completion(false, error)를 호출하고 종료.
  • 사용자 객체 확인:
    • result?.user에서 사용자가 생성되지 않았을 경우 completion(false, nil)로 종료.

 

Firestore - 사용자 데이터 저장

let db = Firestore.firestore()

db.collection("users")
    .document(resultUser.uid)
    .setData([
        "username": username,
        "email": email
    ]) { error in
        if let error = error {
            completion(false, error)
            return
        }
        
        completion(true, nil)
    }

 

 

  • Firestore에 사용자 정보 저장:
    • Firebase Firestore의 users 컬렉션에 새 문서를 추가.
    • 문서 ID는 resultUser.uid(Firebase Authentication에서 생성된 고유 사용자 ID).
    • 데이터 필드:
      • username: 사용자가 입력한 사용자 이름.
      • email: 사용자가 입력한 이메일 주소.
  • 에러 처리:
    • Firestore 저장 중 오류가 발생하면 completion(false, error)를 호출.
  • 성공 처리:
    • Firestore에 데이터가 성공적으로 저장되면 completion(true, nil)을 호출.

 

2. 작동 흐름

  1. 사용자 입력:
    • 사용자가 이메일, 비밀번호, 사용자 이름을 입력하고 registerUser 호출.
  2. Firebase Authentication:
    • 입력한 이메일과 비밀번호를 사용해 Firebase에서 새 사용자를 생성.
    • 사용자가 성공적으로 생성되면 해당 사용자의 고유 ID(uid)를 가져옴.
  3. Firestore 저장:
    • 생성된 사용자 ID(uid)를 사용해 Firestore에 새 문서를 생성.
    • 문서에는 사용자 이름(username)과 이메일(email)이 저장됨.
  4. 결과 반환:
    • 성공적으로 저장되면 completion(true, nil) 호출.
    • 오류가 발생하면 해당 오류 정보를 함께 반환.

 

3. 예제 사용

사용자 등록 요청

 

let userRequest = RegisterUserRequest(username: "JohnDoe", email: "johndoe@example.com", password: "password123")

AutheService.shared.registerUser(with: userRequest) { wasRegistered, error in
    if wasRegistered {
        print("User registered successfully.")
    } else if let error = error {
        print("Failed to register user: \(error.localizedDescription)")
    } else {
        print("Unknown error occurred.")
    }
}