Firebase에서 유저 정보 가져오기

이세진·2022년 6월 24일
0

iOS

목록 보기
23/46
post-custom-banner

생성일: 2022년 1월 18일 오후 10:21

선요약

  1. ProfileController.swift에서 fetchUser() 함수를 생성하여 유저 정보를 가져오도록 한다. 이를 위해 UserService라는 구조체를 생성한다.
  2. UserService는 Firebase에서 유저 정보(딕셔너리 타입)를 가져오고 User 클래스(Model)의 객체로 저장한다.
  3. ProfileController가 User 객체를 받게 되면(didSet으로 확인) 콜렉션 뷰를 reload 하여 navigationItem.title을 유저 이름으로 수정한다.
  4. Profile Header 또한 유저 정보가 들어가도로 수정해야 한다. ⇒ 이를 위해 ProfileHeaderViewModel 생성
  5. ProfileController.swift에서 ProfileHeader로 해당 viewModel을 보낸다.
  6. ProfileHeader에서는 받은 viewModel 정보를 바탕으로 프로필 이미지와 이름을 화면에 띄운다.

ProfileController.swift


class ProfileController: UICollectionViewController {
    
    //MARK: - Properties
    
    var user: User? {
        // reloadeData()를 해줘야 user 객체가 생성된 뒤에 콜랙션뷰가 갱신되서 유저 정보가 화면에 나오게 된다.
        didSet { collectionView.reloadData() }
    }
//MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureCollectionView()
        
        fetchUser()
    }
    
    //MARK: - API
    
    func fetchUser() {
        UserService.fetchUser { user in
            self.user = user
            self.navigationItem.title = user.username
        }
    }
	... 중략 ...
		// 커스텀 헤더를 사용하기 위해 필요한 함수
    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! ProfileHeader
        
        // 처음 이 함수가 호출 되었을 때는 user객체가 생성되기 전이기 때문에 안전하게 if let으로 unwrapping 해야 한다. (collectionView.reloadData()가 실행되면 이 함수가 다시 실행되고 그때는 user 객체가 생성된 후이다.)
        if let user = user {
            header.viewModel = ProfileHeaderViewModel(user: user)
        }
        
        return header
        
    }
}

UserService.swift

import Firebase

// 현재 사용중인 유저 정보 가져오기
struct UserService {
    static func fetchUser(completion: @escaping(User) -> Void) {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        COLLECTION_USERS.document(uid).getDocument { snapshot, error in
            guard let dictionary = snapshot?.data() else { return }
            
            let user = User(dictionary: dictionary)
            completion(user)
        }
    }
}
  • 여기서 함수의 매개변수로 completion이라는 것을 받아온다 ⇒ swift에서는 함수의 매개변수로 함수를 받아올 수 있다. ⇒ 클로져로 작동하여 위와 같은 예시에서는 user 객체를 함수 호출자에게 반환하는 역할을 한다.

User.swift (Model)

import Foundation

struct User {
    let email: String
    let fullname: String
    let profileImage: String
    let username: String
    let uid: String
    
    init(dictionary: [String: Any]) {
        self.email = dictionary["email"] as? String ?? ""
        self.fullname = dictionary["fullname"] as? String ?? ""
        self.profileImage = dictionary["profileImageUrl"] as? String ?? ""
        self.username = dictionary["username"] as? String ?? ""
        self.uid = dictionary["uid"] as? String ?? ""
    }
    
}

ProfileHeaderViewModel.swift (ViewModel)

import Foundation

struct ProfileHeaderViewModel {
    let user: User
    
    var fullname: String {
        return user.fullname
    }
    
    var profileImageUrl: URL? {
        return URL(string: user.profileImage)
    }
    
    init(user: User) {
        self.user = user
    }
}

ProfileHeader.swift

import UIKit
import SDWebImage

class ProfileHeader: UICollectionReusableView {
    
    //MARK: - Properties
    
    var viewModel: ProfileHeaderViewModel? {
        didSet { configure() }
    }

... 중략 ...

	func configure() {
	        guard let viewModel = viewModel else { return }
	        
	        nameLabel.text = viewModel.fullname
	        ProfileImageView.sd_setImage(with: viewModel.profileImageUrl)
	        
	    }
}

정리

  • mvvm 형식을 따르기 위해 didSet 을 이용하여 일부라도 reactive한 구조로 구성하려 했다.
  • 물론 실제 현업에서는 rxSwift나 Combine을 이용하여 mvvm을 구성하는 것으로 알고 있다.
  • 위의 코드에서 사실 ProfileHeaderViewModel 은 없어도 된다. 대신에 User 객체로 유저 정보와 관련된 ui변경을 처리하면 되기는 하지만 이것은 MVC 패턴에 가깝기 때문에 ViewModel를 굳이 만들어서 ProfileHeader와 연결시켜 사용하였다.
profile
나중은 결코 오지 않는다.
post-custom-banner

0개의 댓글