Building Subscription Blogging App: Part 5 – Sign In/Sign Up (2021, Xcode 12, Swift 5) – iOS
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
이 더 간단한 방법이었다.