AutheService
import Foundation
import FirebaseAuth
import FirebaseFirestore
class AutheService {
...
public func signIn(with userRequest: LoginUserRequest,
completion: @escaping (Error?) -> Void) {
let email = userRequest.email
let password = userRequest.password
Auth.auth().signIn(withEmail: email, password: password) { result, error in
if let error = error {
completion(error)
return
} else {
completion(nil)
}
}
}
public func signOut(completion: @escaping (Error?) -> Void) {
do {
try Auth.auth().signOut()
completion(nil)
} catch let error {
completion(error)
}
}
}
위 코드는 Firebase Authentication을 활용해 사용자 로그인과 로그아웃을 처리하는 메서드를 정의한 부분입니다.
1. 메서드 설명
1.1 signIn 메서드
public func signIn(with userRequest: LoginUserRequest,
completion: @escaping (Error?) -> Void)
- 목적: 사용자의 이메일과 비밀번호를 기반으로 Firebase Authentication을 사용해 로그인을 수행합니다.
- 매개변수:
- userRequest: 사용자의 로그인 정보(이메일, 비밀번호)가 담긴 객체.
- completion: 비동기 작업 완료 후 결과를 전달하기 위한 클로저.
- 클로저의 매개변수:
- Error?: 로그인 성공 시 nil, 실패 시 발생한 오류 객체.
- 클로저의 매개변수:
- 작동 흐름:
- Auth.auth().signIn(withEmail: password) 호출.
- Firebase Authentication 서버와 통신 후, 성공 여부와 오류 정보를 반환.
- 결과를 completion 클로저로 전달:
- 성공: completion(nil).
- 실패: completion(error).
1.2 signOut 메서드
public func signOut(completion: @escaping (Error?) -> Void)
- 적: 현재 로그인한 사용자를 로그아웃합니다.
- 매개변수:
- completion: 비동기 작업 완료 후 결과를 전달하기 위한 클로저.
- 클로저의 매개변수:
- Error?: 로그아웃 성공 시 nil, 실패 시 발생한 오류 객체.
- 클로저의 매개변수:
- completion: 비동기 작업 완료 후 결과를 전달하기 위한 클로저.
- 작동 흐름:
- Auth.auth().signOut() 호출.
- Firebase Authentication의 세션을 종료.
- 결과를 completion 클로저로 전달:
- 성공: completion(nil).
- 실패: completion(error) (예: 로그아웃 중 문제가 발생한 경우).
2. 접근 제어자 public의 역할
2.1 public의 의미
- public 접근 제어자는 모듈 외부에서도 해당 메서드에 접근 가능하도록 허용합니다.
- 모듈: 앱을 구성하는 코드의 단위. 기본적으로 동일한 프로젝트 내부 코드가 하나의 모듈을 이룹니다.
- 외부 모듈: 프로젝트에서 가져온 외부 프레임워크 또는 라이브러리.
2.2 왜 public을 사용했는가?
- signIn과 signOut 메서드는 앱 전역에서 사용해야 하는 기능입니다.
- 예: 사용자 인증은 로그인 화면, 설정 화면 등 다양한 곳에서 호출될 수 있습니다.
- public 키워드를 사용하면, 앱의 다른 모듈 또는 다른 뷰 컨트롤러에서도 이 메서드를 호출할 수 있습니다.
2.3 public을 사용하지 않으면?
- 기본 접근 제어자인 internal이 적용됩니다.
- internal: 동일 모듈 내에서만 접근 가능.
- 즉, 동일 프로젝트 내에서는 사용할 수 있지만, 다른 모듈에서는 사용할 수 없습니다.
3. 꼭 public을 써야 할까?
언제 public을 사용해야 하는가?
- 이 클래스가 외부 프레임워크 또는 라이브러리로 제공되는 경우.
- 예: AuthService를 별도의 모듈로 만들고, 다른 프로젝트에서 사용할 경우.
언제 internal로 충분한가?
- 클래스와 메서드가 프로젝트 내에서만 사용되는 경우.
- 만약 AuthService가 이 앱 프로젝트 내에서만 사용된다면 internal로 충분합니다. (public을 제거하면 기본적으로 internal이 됩니다.)
로그인 사용
let userRequest = LoginUserRequest(email: "johndoe@example.com", password: "password123")
AuthService.shared.signIn(with: userRequest) { error in
if let error = error {
print("Sign-in failed: \(error.localizedDescription)")
} else {
print("Sign-in successful!")
}
}
로그아웃 사용
AuthService.shared.signOut { error in
if let error = error {
print("Sign-out failed: \(error.localizedDescription)")
} else {
print("Sign-out successful!")
}
}
결론
- public 사용 이유:
- signIn과 signOut 메서드를 앱 전역에서 호출할 수 있도록 하기 위함.
- 외부 모듈이나 프레임워크로 제공할 경우 필수.
- public 없이도 되는 경우:
- 클래스와 메서드가 동일 프로젝트 내에서만 사용될 때는 기본 접근 제어자인 internal로 충분.
- 클로저의 역할:
- Firebase와 같은 비동기 작업의 결과를 호출자에게 전달하기 위한 방식. 결과로 Error?를 전달하며, 성공 여부를 알려줌.
SceneDelegate
import UIKit
import FirebaseAuth
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
self.setupWindow(with: scene)
self.checkAuthentication()
}
private func setupWindow(with scene: UIScene) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
self.window = window
self.window?.makeKeyAndVisible()
}
public func checkAuthentication() {
if Auth.auth().currentUser == nil {
// Go to sign in screen
self.goToController(with: LoginController())
} else {
// Go to home Screen
self.goToController(with: HomeController())
}
}
private func goToController(with viewController: UIViewController) {
DispatchQueue.main.async { [weak self] in
UIView.animate(withDuration: 0.25) {
self?.window?.layer.opacity = 0
} completion: { [weak self] _ in
let nav = UINavigationController(rootViewController: viewController)
nav.modalPresentationStyle = .fullScreen
self?.window?.rootViewController = nav
UIView.animate(withDuration: 0.25) { [weak self] in
self?.window?.layer.opacity = 1
}
}
}
}
}
위 코드는 SceneDelegate 클래스의 구현으로, iOS 앱에서 여러 씬(Scene)을 관리하기 위해 사용됩니다. 특히, 이 코드는 Firebase Authentication을 사용하여 사용자가 로그인 상태인지 확인하고, 로그인 여부에 따라 적절한 화면(로그인 화면 또는 홈 화면)을 표시하는 기능을 제공합니다.
1. 주요 구성 요소
1.1 scene(_:willConnectTo:options:)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
self.setupWindow(with: scene)
self.checkAuthentication()
}
- 역할:
- 앱의 특정 씬이 연결될 때 호출됩니다.
- 앱의 기본적인 초기화를 수행합니다.
- 이 메서드에서 setupWindow와 checkAuthentication 메서드를 호출합니다.
- 동작 흐름:
- setupWindow(with:):
- UIWindow를 설정하고 화면에 표시.
- checkAuthentication():
- Firebase Authentication을 사용하여 로그인 여부를 확인하고, 로그인 상태에 따라 적절한 화면으로 전환.
- setupWindow(with:):
1.2 setupWindow(with:)
private func setupWindow(with scene: UIScene) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
self.window = window
self.window?.makeKeyAndVisible()
}
- 역할:
- 앱의 UIWindow를 생성하고 활성화.
- UIWindow는 앱의 모든 UI 요소를 표시하는 컨테이너 역할을 합니다.
- 이 메서드는 UIScene 객체를 받아 UIWindowScene을 생성하고 UIWindow에 연결합니다.
1.3 checkAuthentication()
public func checkAuthentication() {
if Auth.auth().currentUser == nil {
// Go to sign in screen
self.goToController(with: LoginController())
} else {
// Go to home Screen
self.goToController(with: HomeController())
}
}
- 역할:
- Firebase Authentication을 사용하여 로그인 상태를 확인.
- Auth.auth().currentUser를 사용해 현재 로그인된 사용자가 있는지 검사:
- nil인 경우:
- 사용자가 로그인하지 않았으므로 로그인 화면(LoginController)으로 이동.
- 로그인 상태인 경우:
- 홈 화면(HomeController)으로 이동.
- nil인 경우:
1.4 goToController(with:)
private func goToController(with viewController: UIViewController) {
DispatchQueue.main.async { [weak self] in
UIView.animate(withDuration: 0.25) {
self?.window?.layer.opacity = 0
} completion: { [weak self] _ in
let nav = UINavigationController(rootViewController: viewController)
nav.modalPresentationStyle = .fullScreen
self?.window?.rootViewController = nav
UIView.animate(withDuration: 0.25) { [weak self] in
self?.window?.layer.opacity = 1
}
}
}
}
- 역할:
- 특정 화면으로 전환하며, 전환 과정에서 페이드 애니메이션을 적용.
- 새 UIViewController를 UINavigationController에 래핑하여 표시.
- 동작 흐름:
- 첫 번째 애니메이션:
- self?.window?.layer.opacity = 0로 설정하여 현재 화면을 점점 투명하게 만듦.
- 화면 전환:
- self?.window?.rootViewController를 새로운 UIViewController로 설정.
- 두 번째 애니메이션:
- self?.window?.layer.opacity = 1로 설정하여 새로운 화면을 점점 불투명하게 표시.
- 첫 번째 애니메이션:
- DispatchQueue.main.async 사용:
- UI 작업은 메인 스레드에서 실행되어야 하므로 안전하게 UI 업데이트를 보장.
- weak self 사용:
- 메모리 누수를 방지하기 위해 [weak self]를 사용하여 클로저 내부에서 self를 약하게 참조.
2. 코드의 동작 흐름
- 앱 실행 시 scene(_:willConnectTo:options:) 호출:
- setupWindow(with:)를 통해 UIWindow를 초기화.
- checkAuthentication()를 호출하여 로그인 상태 확인.
- 로그인 여부에 따라 화면 전환:
- Firebase Authentication에서 현재 사용자를 확인:
- 로그인하지 않은 상태: 로그인 화면(LoginController) 표시.
- 로그인 상태: 홈 화면(HomeController) 표시.
- Firebase Authentication에서 현재 사용자를 확인:
- 화면 전환 애니메이션:
- goToController(with:)를 사용해 부드러운 페이드 애니메이션을 통해 화면 전환.
- goToController(with:)를 사용해 부드러운 페이드 애니메이션을 통해 화면 전환.
3. 코드에 사용된 주요 기술
3.1 Firebase Authentication
- Auth.auth().currentUser:
- 현재 로그인된 사용자의 정보를 가져옴.
- 로그인되지 않은 경우 nil을 반환.
3.2 UIWindow 및 UIWindowScene
- UIWindow:
- 앱의 UI 요소를 포함하는 컨테이너.
- 앱에서 화면을 표시하려면 UIWindow를 초기화하고 활성화해야 함.
- UIWindowScene:
- iOS 13 이후, 멀티윈도우를 지원하기 위해 추가된 씬 관리 객체.
3.3 UIView 애니메이션
- UIView.animate:
- 간단한 애니메이션을 적용하는 메서드.
- 여기서는 페이드 효과(투명도 변화)를 사용해 부드러운 화면 전환 구현.
🔥 로그인 상태 캐싱:
- 로그인 상태를 로컬 스토리지에 캐싱하여 매번 Firebase Authentication 호출을 줄일 수 있음.
'Project > FirebaseTest' 카테고리의 다른 글
FireBase - 사용자 정보 불러오기 및 사용자 삭제 (0) | 2024.12.04 |
---|---|
FireBase - 유효성 검사 + 사용자 등록 (0) | 2024.12.03 |
FireBase - 사용자 등록 기능 (0) | 2024.12.03 |
FireBase - Alert (0) | 2024.12.03 |
FireBase - UITextView with open WKWebView (0) | 2024.12.03 |