簡體   English   中英

iOS swift 應用程序在滾動到底部時終止於 TableView

[英]iOS swift app terminating on TableView when scrolled to bottom

我正在使用Firebase在我的 iOS 應用程序中填充TableView 前幾個對象已加載,但是一旦我到達列表中的第三項,應用程序就會崩潰,但有以下異常:

'NSRangeException', reason: '*** __boundsFail: index 3 beyond bounds [0 .. 2]'

我知道這意味着我指的是一個不包含索引的數組,但我不知道為什么。

我使用TableViewController TableView像這樣初始化它:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print(posts.count)
        return posts.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let post = posts[indexPath.row]
        print(post)
        let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath) as! PostCell

        let firstReference = storageRef.child(post.firstImageUrl)
        let secondReference = storageRef.child(post.secondImageUrl)

        cell.firstTitle.setTitle(post.firstTitle, for: .normal)
        cell.secondTitle.setTitle(post.secondTitle, for: .normal)
        cell.firstImageView.sd_setImage(with: firstReference)
        cell.secondImageView.sd_setImage(with: secondReference)

        // Configure the cell...

        return cell
    }

我相信第一個 function 創建了一個包含posts中對象數量的數組,第二個 function 將值分配給單元格的模板。 第一種方法中的打印語句打印 4,這是從 firebase 檢索到的正確對象數。 我假設這意味着創建了一個數組,其中包含要在TableView中顯示的 4 個對象。 這是真正令人困惑的地方,因為錯誤表明數組中只有 3 個對象。 我是否誤解了TableView是如何實例化的?

這是填充TableView的代碼:

func loadMessages(){
        db.collectionGroup("userPosts")
            .addSnapshotListener { (querySnapshot, error) in

            self.posts = []

            if let e = error{
                print("An error occured trying to get documents. \(e)")
            }else{
                if let snapshotDocuments = querySnapshot?.documents{
                    for doc in snapshotDocuments{
                        let data = doc.data()
                        if let firstImage = data[K.FStore.firstImageField] as? String,
                            let firstTitle = data[K.FStore.firstTitleField] as? String,
                            let secondImage = data[K.FStore.secondImageField] as? String,
                            let secondTitle = data[K.FStore.secondTitleField] as? String{
                            let post = Post(firstImageUrl: firstImage, secondImageUrl: secondImage, firstTitle: firstTitle, secondTitle: secondTitle)
                            self.posts.insert(post, at: 0)
                            print("Posts: ")
                            print(self.posts.capacity)
                            DispatchQueue.main.async {
                                self.tableView.reloadData()
                            }
                        }
                    }
                }
            }
        }

該應用程序構建並運行並顯示前幾個項目,但一旦我滾動到列表底部就會崩潰。 任何幫助是極大的贊賞。

編輯:

override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.register(UINib(nibName: K.cellNibName, bundle: nil), forCellReuseIdentifier: K.cellIdentifier)
        loadMessages()
    }

由於您正在危險地填充數據源,因此您遇到了越界錯誤。 您必須記住,表格視圖在滾動時會不斷添加和刪除單元格,這使得更新其數據源成為一項敏感任務。 您在每次文檔迭代時重新加載表,並在數據源中的索引0處插入一個新元素。 更新期間的任何滾動都會引發越界錯誤。

因此,填充一個臨時數據源並在它准備好時將其交給實際數據源(然后立即重新加載表,在更改的數據源和從該數據源獲取的活動滾動之間不留任何空間)。

private var posts = [Post]()
private let q = DispatchQueue(label: "userPosts") // serial queue

private func loadMessages() {
    db.collectionGroup("userPosts").addSnapshotListener { [weak self] (snapshot, error) in
        self?.q.async { // go into the background (and in serial)
            guard let snapshot = snapshot else {
                if let error = error {
                    print(error)
                }
                return
            }
            var postsTemp = [Post]() // setup temp collection
            for doc in snapshot.documents {
                if let firstImage = doc.get(K.FStore.firstImageField) as? String,
                    let firstTitle = doc.get(K.FStore.firstTitleField) as? String,
                    let secondImage = doc.get(K.FStore.secondImageField) as? String,
                    let secondTitle = doc.get(K.FStore.secondTitleField) as? String {
                    let post = Post(firstImageUrl: firstImage, secondImageUrl: secondImage, firstTitle: firstTitle, secondTitle: secondTitle)
                    postsTemp.insert(post, at: 0) // populate temp
                }
            }
            DispatchQueue.main.async { // hop back onto the main queue
                self?.posts = postsTemp // hand temp off (replace or append)
                self?.tableView.reloadData() // reload
            }
        }
    }
}

除此之外,我將在后台處理此問題(Firestore 在主隊列上返回),並且僅在修改數據源時才重新加載表。

經過一番擺弄和實施@bsod 的響應后,我能夠讓我的項目運行起來。 解決方案位於屬性檢查器下的Main.Storyboard中,我必須將內容設置為動態原型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM