• query
  • Refactor : ImageIndexObserver
  • Pagination data
  • Refresh fetching users
  • fix some problems
  • Add Hud to refreshing action

rename setupDummyCards() to setupFirestoreUserCards()

        let query = Firestore.firestore().collection("users")
        query.getDocuments { (snapshot, err) in
            if let err = err {
.whereField("age", isEqualTo: 26)
.whereField("profession", isEqualTo: "Student")
.whereField("age", isLessThan: 31).whereField("age", isGreaterThan: 24)

profession과 age, 하나의 필드에 대해 두개의 where함수 사용은 에러를 반환한다.

        let query = Firestore.firestore().collection("users")
            .whereField("age", isLessThan: 31)
            .whereField("age", isGreaterThan: 24)
            .whereField("friends", arrayContains: "동준")

it doesn’t work

"The query requires an index. You can create it here: https://console.firebase.google.com/project/tinderswipematchfirestor-afc99/database/firestore/indexes?
        let query = Firestore.firestore().collection("users")
            .whereField("friends", arrayContains: "동준")

it works

Imgae transparent bug

    var imageIndexObserver: ((Int, String?) -> ())?
    fileprivate var imageIndex = 0 {
        didSet {
            let imageUrl1 = imageNames[imageIndex]
//            let image = UIImage(named: imageName)
            imageIndexObserver?(imageIndex, imageUrl1)
    fileprivate func setupImageIndexObserver() {
        cardViewModel.imageIndexObserver = { [weak self] (index, imageUrl) in
            if let url = URL(string: imageUrl ?? "") {
                self?.imageView.sd_setImage(with: url)
            self?.barsStackView.arrangedSubviews.forEach({ (v) in
                v.backgroundColor = self?.barDeselectedColor
            self?.barsStackView.arrangedSubviews[index].backgroundColor = .white

Pagination Data Fetch

데이터가 많기 때문에 page로 분할하여 데이터 중 일부만 반환하게 한다.

Firestore Pagination Documentation : 쿼리 커서로 데이터 페이지화

작은 데이터 덩어리들로 쪼개고 싶다.

batch : 한 묶음 [다발, 무리]

I will introduce pagination here to page through 2 users at a time

    var lastFetchedUser: User?
            snapshot?.documents.forEach({ (documentSnapshot) in
                let userDictionary = documentSnapshot.data()
                let user = User(dictionary: userDictionary)
                self.lastFetchedUser = user

lastFetchedUser는 현재 Firebase에 등록된 개수만큼 실행된다.

lastFetchedUser는 array일 필요는 없다. 이미 order로 정렬되어서 가져와진 데이터이기 때문에 마지막에 fetch된 user만 저장해 놓은 후에 그 뒤(start(from: ~))부터 가져온 snapshot에서 데이터가 오기 때문에 겹치지 않는다.

일단은 uid로 정렬하는데 uid는 unique & generated randomly

    .order(by: "uid")
    .start(after: lastFetchedUser?.uid ?? "")
    .limit(to: 2)


2개 씩 불러오는데 이를 다시 불러오도록 한다.

일단 버튼 활성화를 위해서 버튼을 손쉽게 만드는 함수를 구현한다.

    static func createButton(image: UIImage) -> UIButton {
        let button = UIButton(type: .system)
        button.setImage(image, for: .normal)
        button.imageView?.contentMode = .scaleAspectFill
        return button

    let refreshButton = createButton(image: #imageLiteral)
    let dislikeButton = createButton(image: #imageLiteral)
    let superLikeButton = createButton(image: #imageLiteral)
    let likeButton = createButton(image: #imageLiteral)
    let specialButton = createButton(image: #imageLiteral)

using forEach in array is always right :)

        [refreshButton, dislikeButton, superLikeButton, likeButton, specialButton].forEach { (button) in

Don’t forget set images with RenderingMode

        button.setImage(image.withRenderingMode(.alwaysOriginal), for: .normal)

refactoring method name, addTarget to refreshButton

// HomeController.swift

    let bottomControls = HomeBottomControlsStackView()

        bottomControls.refreshButton.addTarget(self, action: #selector(handleRefresh), for: .touchUpInside)
    @objc fileprivate func handleRefresh() {

problem1 : everytime we click the refreshButton, previous cardViews are generated together

Because we stored our cardViewModel to cardViewModels array when user is generated. So make a new func for setupCardView. It’s really simular to previous function setupCardFromFirestore()

    fileprivate func setupCardFromUser(user: User) {
        let cardView = CardView(frame: .zero)
        cardView.cardViewModel = user.toCardViewModel()

We can setup cardview when user is generated instantly.

            snapshot?.documents.forEach({ (documentSnapshot) in
                let userDictionary = documentSnapshot.data()
                let user = User(dictionary: userDictionary)
                self.lastFetchedUser = user
                self.setupCardFromUser(user: user)

Problem2 : we can see cards are being stacked in cardsDeckView

// func setupCardFromUser()


Everytime we fire off fetchUsersFromFirestore(), make a hud

    fileprivate func fetchUsersFromFirestore() {
        let hud = JGProgressHUD(style: .dark)
        hud.textLabel.text = "fetching users"
        hud.show(in: view)

and dismiss it when it get documents

        query.getDocuments { (snapshot, err) in
            if let err = err {
                print("Failed to fetch users :", err)