[Swift]Model 동기화
트위터 클론 코딩 & Firebase 사용

가볍게 봐주시면 감사합니다 😁

Tweet 피드 중 기존 "좋아요" 데이터 불러오기

이슈 ▾

좋아요 버튼 클릭 여부 카운팅되지 않음

  • 기존에 좋아요를 눌렀던 피드가 앱을 재접속하여 다시 누르면 또 다시 좋아요가 카운팅된다.
  • 사용자가 좋아요를 눌렀는지에 대한 여부를 체크하여 View가 보여질 때 데이터도 함께 동기화가 되어야 한다.

 

원인 ▾

  • Tweet - Model
struct Tweet {
    let caption: String
    let tweetID: String
    let uid: String
    var likes: Int
    var timestamp: Date!
    let retweetCount:  Int
    var user: User
    var didLike = false			// 이 부분
    
    // ...

}
  • 기존 좋아요를 판별하기 위한 Bool 타입 didLike가 false로 초기화가 되기 때문에, 좋아요를 누른 뒤 앱을 재접속하면 true여야 되는 값도 false로 되어 있게 된다.

 

해결 ▾

  • 내가 원하는 것
    • Tweet(Model)으로 피드를 업데이트하고, 업데이트 된 피드(데이터)를 기반으로 사용자가 트윗을 좋아했는지 확인하기
      • 만약, UI를 업데이트하기 전에 사용자가 트윗을 좋아요를 누르면, 작업이 더 오래 걸리고, DB에서 많은 불필요한 작업 수행
    • 사용자가 해당 트윗을 좋아하면 사용자 인터페이스 업데이트 하기
    • 모든 항목을 확인하면 데이터 소스를 업데이트 하기

 

  • TweetService - API
/// 트윗 좋아요 눌렀는지 체크하는 API
func checkIfUserLikedTweet(_ tweet: Tweet, completion: @escaping(Bool) -> Void) {
    guard let uid = Auth.auth().currentUser?.uid else { return }
    
    REF_USER_LIKES.child(uid).child(tweet.tweetID).observeSingleEvent(of: .value) { snapshot in
        completion(snapshot.exists())
    }
}
  • 현재 사용자의 ID를 가져오고, 해당 ID를 가지고 DB에 좋아요 누른부분이 존재하는지 체크한다.
  • observeSingleEvent ▾

Firebase-Doc

  • snapshot
    • 하위 데이터를 포함하여 해당 위치의 모든 데이터를 포함하는 snapshot이 이벤트 콜백에 전달됨
  • exsits() ▾

  • 해석하면, "DataSnapshot에 null이 아닌 값이 포함되면 yes를 반환합니다." 라고 한다.
  • 즉, 데이터가 null이 아니면 true값이 반환된다고 보면 된다.

 

  • FeedController - Controller
/// 트윗 데이터 불러오기
func fetchTweets() {
    TweetService.shared.feetchTwetts { tweets in
        self.tweets = tweets
        self.checkIfUserLikedTweets(self.tweets)
    }
}

/// 트윗 좋아요 데이터 불러오기
func checkIfUserLikedTweets(_ tweets: [Tweet]) {
    for (index, tweet) in tweets.enumerated() {
        TweetService.shared.checkIfUserLikedTweet(tweet) { didLike in
            guard didLike == true else { return }
            
            self.tweets[index].didLike = true
        }
    }
}
  • checkIfUserLikedTweets(_ tweets: [Tweet])
    • tweets.enumerated()

      • "(n, x)의 시퀀스를 반환하는데, 여기서 n은 0에서 시작하는 연속적인 정수를 나타내고, x는 시퀀스의 요소를 나타낸다."
      • 즉, tweets의 데이터를 해당 index에 맞는 tweet을 하나하나 순회한다고 보면 된다. 
    • gurad didLike == true else { return } 
      • didLike가 true값이 아니면 return
      • true값이면 tweets의 해당 index에 didLike의 값을 true로 변경

 

  • tweets의 didLike가 true값으로 변경이 되면 didSet을 이용하여 collectionView를 새로고침 해준다.
private var tweets = [Tweet]() {
    didSet { collectionView.reloadData() }
}

 

  • reloadData()가 호출이 되면 자연스럽게 cellForItemAt이 호출이 된다.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! TweetCell
    
    cell.delegate = self
    cell.tweet = self.tweets[indexPath.row]
    
    return cell
}
  • 이렇게 되면, cell은 다시 tweet 데이터를 가지고 UI를 업데이트 하게 되는 것이다.

 

  • TweetCell - View
// TweetCell (View)
var tweet: Tweet? {
    didSet { configureUI() }
}

func configureUI() {
    guard let tweet = tweet else { return }
    let viewModel = TweetViewModel(tweet: tweet)
    captionLabel.text = tweet.caption
    
    profileImageView.sd_setImage(with: viewModel.profileImageUrl)
    infoLabel.attributedText = viewModel.userInfoText
    likeButton.tintColor = viewModel.likeButtonTintColor
    likeButton.setImage(viewModel.likeButtonImage, for: .normal)
}
  • TweetCell의 데이터도 역시 변하게 되면서 configureUI() 메서드가 호출이 되고, 해당 viewModel을 통해 view에 관련 데이터가 가공이 되는 것이다.

'Udemy.zip' 카테고리의 다른 글

[Swift]RxSwift 기초 문법  (0) 2022.04.13
[Swift] Firebase 기능  (0) 2022.03.25
[Swift]Table View 이슈  (0) 2022.03.05
[Swift]ActionSheet-Protocol  (0) 2022.02.25