[UIKit] BlogClone: Auth

Junyoung Park·2022년 11월 23일
0

UIKit

목록 보기
99/142
post-thumbnail

Building Subscription Blogging App: Part 5 – Sign In/Sign Up (2021, Xcode 12, Swift 5) – iOS

BlogClone: Auth

구현 목표

  • 파이어베이스 회원가입 및 로그인 구현

구현 태스크

  • AuthManager 싱글턴 클래스를 통한 중앙 관리 → SceneDelegate를 통한 루트 뷰 교체
  • Codable 프로토콜을 통한 데이터 변환 및 데이터베이스 등록
  • PHPickerViewController를 통한 이미지 선택

핵심 코드

private func bind(with scene: UIWindowScene) {
        let window = UIWindow(windowScene: scene)
        window.makeKeyAndVisible()
        self.window = window
        AuthManager.shared.userSession
            .removeDuplicates()
            .sink { user in
                let option: UIView.AnimationOptions = user == nil ? .transitionFlipFromRight : .transitionFlipFromLeft
                UIView.transition(with: window, duration: 0.2, options: option) {
                    if user != nil {
                        window.rootViewController = TabBarViewController()
                    } else {
                        let vc = SignInViewController()
                        vc.title = "Sign In"
                        let nav = UINavigationController(rootViewController: vc)
                        nav.navigationItem.largeTitleDisplayMode = .always
                        nav.navigationBar.prefersLargeTitles = true
                        window.rootViewController = nav
                    }
                }
            }
            .store(in: &cancellables)
    }
  • SceneDelegate 자체에서 AuthManager가 관리하고 있는 유저 세션 값을 구독, 루트 뷰를 변환하는 부분
  • UIView.transition 애니메이션을 통해 루트 뷰 변환을 자연스럽게 구현
func register(email: String, userName: String, password: String, completion: @escaping(Bool) -> Void) {
        Auth.auth().createUser(withEmail: email, password: password) { [weak self] result, error in
            guard
                let user = result?.user,
                error == nil else {
                completion(false)
                return
            }
            self?.tempUserSession = user
            let data = ["email": email, "userName": userName.lowercased()]
            Firestore.firestore().collection("users")
                .document(user.uid)
                .setData(data) { [weak self] error in
                    if let error = error {
                        print(error.localizedDescription)
                        completion(false)
                    } else {
                        self?.didAuthenticateUser = true
                        print("Firestore Register Did Succeed")
                        completion(true)
                    }
                }
        }
    }
  • 회원가입 로직 구현
  • 파이어베이스 내 회원가입 후 생성되는 토큰을 임시 토큰으로 받은 뒤 사진을 입력받을 준비 완료
func uploadProfileImage(with image: UIImage) {
        guard let uid = tempUserSession?.uid else { return }
        ImageUploader.uploadImage(image: image, folder: .profileImage) { [weak self] result in
            switch result {
            case .failure(let error): print(error.localizedDescription)
            case .success(let urlString):
                let data = ["profileImageURL": urlString]
                Firestore.firestore().collection("users")
                    .document(uid)
                    .setData(data, merge: true) { [weak self] error in
                        if let error = error {
                            print(error.localizedDescription)
                        } else {
                            self?.didAuthenticateUser = false
                            self?.userSession.send(self?.tempUserSession)
                            self?.tempUserSession = nil
                        }
                    }
            }
        }
    }
  • userSession에 이미지 업로드 완료 확인 이후 이전에 저장해놓은 임시 유저 세션 값을 보냄으로써 SceneDelegate가 루트 뷰를 인증 담당 뷰에서 디폴트 탭바 뷰로 전환할 수 있도록 역할

구현 화면



이전 트위터 클론 과정에서 파이어베이스 스위프트 모듈이 제공하는 디코딩 과정에 보다 익숙해질 수 있어서 편리했다. 강의에서 제공하는 유저의 이메일을 다큐먼트 아이디로 찾아가는 것보다, 유저 세션을 통해 얻을 수 있는 uid이 더 간단한 방법이었다.

profile
JUST DO IT

0개의 댓글