【问题标题】:Reload TableView After Deleting, Adding, or Modifying Firestore Document and Paginating Results删除、添加或修改 Firestore 文档和分页结果后重新加载 TableView
【发布时间】:2020-06-17 11:23:25
【问题描述】:

我正在从 Firebase Firestore 检索文档并在表格视图中显示它们。从表格视图中,我希望能够删除和添加项目。我还从项目详细信息视图修改文档。不过,我将专注于我的问题,删除此问题的项目。通过使用最后一个快照仅获取下一组项目,我的查询得到了分页结果。我还使用侦听器来获取修改项目时的实时更新。删除的问题是如何正确处理它?我目前拥有的内容可以很好地删除项目,但随后会将表格视图中剩余的行加倍。

var items = [Item]()
    var itemQuery: Query?
    var lastSnapshot: QueryDocumentSnapshot?

func getItems() {
    if lastSnapshot == nil {
            itemQuery = Firestore.firestore().collection("items").whereField("collection", isEqualTo: self.collection!.id).order(by: "name").limit(to: 25)
        } else {
            itemQuery = itemQuery?.start(afterDocument: lastSnapshot!)
        }

        itemQuery!.addSnapshotListener( { (snapshot, error) in
            guard let snapshot = snapshot else {
                return
            }

            if snapshot.documents.last != nil {
                self.lastSnapshot = snapshot.documents.last
            } else {
                return
            }

            if let error = error {
                print(error.localizedDescription)
            } else {
                for document in snapshot.documents {
                    let docName = document["name"] as? String
                    let docId = document.documentID
                    let docImages = document["images"] as? [String]
                    let docCollection = document["collection"] as? String
                    let docInfo = document["info"] as? String
                    let docQuantity = document["quantity"] as? Int
                    let item = Item(id: docId, name: docName!, collection: docCollection!, info: docInfo!, images: docImages!, quantity: docQuantity!)
                    self.items.append(item)
                }
                if self.items.count >= 25 {
                    self.addFooter()
                }
                self.tableView.reloadData()
            }
        })
}

func deleteItem(at indexPath: IndexPath) {
        let itemToDelete = items[indexPath.row]

        // Delete images from storage
        for url in itemToDelete.images {
            let store = Storage.storage()
            let storageRef = store.reference(forURL: url)
            storageRef.delete { error in
                if let error = error {
                    print(error.localizedDescription)
                } else {
                    print("Image file deleted successfully")
                }
            }
        }

        Firestore.firestore().collection("items").document(itemToDelete.id).delete() { error in
            if let error = error {
                print(error.localizedDescription)
            } else {
                print("Item deleted")
            }
        }
    }

override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell

        let item = items[indexPath.row]
        cell.itemNameLabel.text = item.name

        if item.images.count > 0 {
            let thumbnailUrl = item.images[0]
            cell.itemImageView.sd_setImage(with: URL(string: thumbnailUrl), placeholderImage: UIImage(named: "photo"), completed: { (image, error, cacheType, imageUrl) in
                cell.itemImageView.roundCornersForAspectFit(radius: 10)
            })
        } else {
            cell.itemImageView.image = UIImage(named: "photo")
        }

        return cell
    }

    // Override to support conditional editing of the table view.
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }

    // Override to support editing the table view.
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            print("Items before delete: \(items.count)")
            deleteItem(at: indexPath)
            // items.removeAll()
            // tableView.reloadData()
            items.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
            print("Items after delete: \(items.count)")
        }
    }

【问题讨论】:

  • 如果部署目标是iOS 13+ 最高效的解决方案是UITableViewDiffableDataSource
  • 那里有相当多的代码,但是当删除一个项目时,通常有两种处理方法。 1)删除 Firebase 中的项目,当您的应用收到删除事件时,从该闭包内的数据源中删除项目,然后更新 UI(使用 tableView.reloadData 刷新 tableView)。选项 2 是一种手动方法,您可以从 Firebase 中删除该项目,忽略生成的事件并手动从您的数据源中删除该项目,然后刷新 tableView。如果这是一个多用户应用程序,则首选选项 1),这样其他用户也将获得删除事件。

标签: ios swift firebase google-cloud-firestore


【解决方案1】:

您可以使用 Property Observer 来处理您的tableView.reloadData()

var items = [Item]() {
    didSet {
        tableView.reloadData()
    }
}

上面的作用是每当变量items被修改时,它都会触发didSet {}代码块。

希望能回答你的问题。

【讨论】:

  • 这并没有真正的帮助,因为我正在使用最后一个文档快照来获取分页结果。
  • 这不是一个好主意。如果您将 25 个项目附加到该数组,则 tableView 将自行重新加载 25 次。将 100 个项目添加到数组中,这将是 100 次重新绘制。这将导致闪烁和奇怪的 UI 体验。 tableViews 应该做的是完全填充 dataSource 数组,然后然后重绘一次。
猜你喜欢
  • 2021-02-08
  • 2020-03-08
  • 2015-10-10
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 1970-01-01
相关资源
最近更新 更多