Swift : Firestore와 collectionView를 사용하여 게시 목록 검색, 업데이트 및 삭제 처리

12485 단어 SwiftFirestore
Firestore에서 SNS적인 유저 투고형의 시스템을 만들 경우, 이하와 같은 사양이 필요하다고 생각한다.
  • 처음에 내림차순 (날짜가 새로운 순서)로 포스트리스트를 표시한다
  • 투고되면 홈 일람을 자동 갱신한다 (이상은 자신의 투고 완료만 자동 갱신)
  • 게시물을 삭제하면 게시물 목록에서 자동으로 삭제합니다
  • 좋아요와 댓글과 같은 Firestore의 필드 가치 업데이트로 다시로드하지 않습니다.



    보다 보다 라이브러리등 있다고 생각하지만 기본적인 CollectionView의 구조만으로 해 보았다.
    구체적으로는 snapshot.documentChangescollectionView.insertItems(at:)/collectionView.deleteItems(at:)

    코드


    import FirebaseFirestore
    
    class ViewController: UIViewController {
    
     @IBOutlet weak var collectionView: UICollectionView!
     var stories: [Story] = []
     let db = Firestore.firestore()
     var storiesListener: ListenerRegistration?
    
     override func viewDidLoad() {
            super.viewDidLoad()
            self.setStoriesListener()
        }
    
    func setStoriesListener() {
            self.storiesListener = self.db.collection("stories")
                .order(by: "createTime", descending: true)  // 降順で(日付が新しい順から)取ってくる
                .addSnapshotListener({ (querySnapshot, error) in
                    guard let snapshot = querySnapshot else {
                        print("Error while getting collection: \(error)")
                        return
                    }
                    snapshot.documentChanges.forEach { diff in
                        if (diff.type == .added) {
                            let story = Story(document: diff.document)
                            let newIndex = Int(diff.newIndex)
                            self.stories.insert(story, at: newIndex) // 投稿を格納している配列のindexとFirestore上のindexを揃えてやる
                            self.collectionView.insertItems(at: [IndexPath(item: newIndex, section: 0)])
                        }
                        if (diff.type == .modified) {
                            // いいねやコメントなどのフィールドバリューの更新はここが呼ばれる
                            // リアルタイムでいいね数やコメント数の変化を反映したい場合は collectionView.reloadItems(at:)を使うはず
                        }
                        if (diff.type == .removed) {
                            let oldIndex = Int(diff.oldIndex)
                            self.stories.remove(at: oldIndex)
                            self.collectionView.deleteItems(at: [IndexPath(item: oldIndex, section: 0)])
                        }
                    }
    
                })
    
    
    extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return self.stories.count
       }
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! StoryCell
            let story = self.stories[indexPath.row] 
            // cellに画像やラベルテキストを設定する処理           
            return cell
        }       
    }
    

    덧붙여서 createTime에서 서버 타임 스탬프를 사용하고 있다고 하면 .added 뒤에 .modefied 가 곧바로 불리는 것에 주의.

    리스너를 설정하는 타이밍



    위에서는 viewDidLoad()로 리스너를 설정하고 있어 Firebase 문서 등에서 볼 수 있는 viewWillAppear가 아니다. 이것은 홈 탭을 이동해 돌아왔을 때마다, 재취득&묘화 처리가 달리는 것을 막고 싶기 때문이다. deinit는 홈 탭의 천이에서는 불리지 않기 때문에 다른 화면에 가도 계속 관관을 계속할 수 있다.

    viewWillApper에서 리스너를 설정하고 viewWillDesaper에서 storiesListener?.remove() 를 호출하지 않게 하면 탭에서 전환해 돌아올 때마다 리스너가 중복 세트 되는 것이 원인인가, 역시 매번 리로드가 달려 버린다.

    누군가 적절한 방법을하고 있다면 알려주세요. 🥺

    reloadData()와 insertItem(at: Index)의 차이



    reloadData를 호출하면 collectionView(_:cellForItemAt:)が collectionView(_:numberOfItemsInSection)`로 반환된 횟수분, 0부터 차례로 불려 셀이 생성된다.

    한편으로 insertItems(at: Index)를 부르면 at 로 지정한 Index만으로 매번 collectionView(_:cellForItemAt) 가 불린다.

    reloadData () 그럼 왜 안돼?



    addSnapshotListener로 항상 감시를 하고 있으면 뭔가의 변경은 전부 픽업한다. 그러나 그럼 , 1개 투고가 있거나 좋네요나 코멘트가 있을 때마다 모든 Cell가 재리로드되어 투고 일람 화면이 치카치카 해 보인 것이 아니게 된다.

    그렇다고 해서 청취를 하지 않고 에서 루트의 View에서 추적 홈 화면 getDocuments 같은 기능을 호출하거나 collectionView를 업데이트하는 것은 어렵고 복잡한 것 같았다).

    그런데 많은 문헌에서는 이런 방식이 거의 없어 고전했다.

    참고한 기사



    insert나 delete를 이용한 깨끗한 갱신은, iOS나 Firestore등에서 신기사를 양산하고 있다 @ 물건씨의 이하 기사가 참고가 되었다.
    htps : // 기 st. 기주 b. m / 0926 / 27131 8 6 1cf27 0dc4b655 240350

    newIndex나 oldIndex의 정확한 이해는 Firebase 공식 문서에
    htps : // 푹 빠져라. 오, ぇ. 코 m / 드 cs / 레후 렌세 / 슈 ft / 푹 푹신 푹신 s 트레 / 아피 / 르후 렌 세 / C ぁ せ s / 도쿠 멘 t 짱
  • 좋은 웹페이지 즐겨찾기