首页 > 解决方案 > 在 UITableView 单元格上快速求和值

问题描述

我有TableView一个视图控制器和一个UILabelUIViewController一切都得到了很好的展示,但我正在努力实现一些目标,我不能简单地得到它背后的逻辑。

tableview 单元格有一个 UILabel,它Int在单元格上具有值,这些数字现在有所不同,我如何获得 tableView 单元格中标签上的数字总和并显示在视图控制器中的标签上。

我尝试在 UIView 控制器中创建一个变量并将这个值添加到 t 但我无法这样做,因为我无法将这个数字加在一起

关于如何做到这一点的任何帮助。谢谢

var total: Double?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        switch indexPath.section {
        case 0:
            let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! BrokageCheckoutCell
            cell.configure()
            total = Double("\(cell.subPrice.text!)")
            cell.selectionStyle = .none
            return cell
        case 1:
            let cell = tableView.dequeueReusableCell(withIdentifier: cellId2, for: indexPath) as! OtherCheckoutCell
            cell.configure()
            cell.selectionStyle = .none
            return cell
        default: break
        }
        return UITableViewCell()
    }

标签: iosswiftuitableview

解决方案


你问:

如何获取 tableView 单元格中标签上的数字总和并显示在视图控制器中的标签上

简而言之,你没有。表格视图单元格中的标签(它是“视图”的一部分)不是我们的数据源。它仅用于显示单个字符串。

例如,假设您的应用程序有 100 个要求和的项目,但应用程序的表格视图一次只显示 12 行。作为内存和性能改进,iOS 将重用滚动到视图之外的单元格,以便显示滚动到视图中的新行的内容。但这意味着您不能说“将这 100 个单元格中标签的所有内容相加”,因为没有 100 个单元格;只有12个。

您的应用程序应该引用它的“模型”,即cellForRowAt用于确定在给定表格视图单元格中显示什么的结构(例如,数组)。所以,如果你想加总,你应该把那个数组中的值加起来,而不是引用单元格。

如果您的单元格具有允许修改数据的控件,则该单元格应启动模型的更新。然后,计算总计(对数组中的值求和)的过程仍然有效。

所以,让我们考虑一个例子:

  1. 您应该有一个模型,其中包含要求和的数字。您的示例有点不清楚,所以我将创建一个示例,其中每个表行包含一个名称、一个单价和一个数量:

    struct Item {
        let name: String
        let unitPrice: Decimal
        var quantity: Decimal
    }
    

    在此示例中,任何给定行的总计将是数量乘以单价。所有行的总计将是所有这些产品的总和。

  2. 然后你的视图控制器可能有一个数组用于它的模型:

    var items: [Item] = ...
    
  3. 然后,当您想更新总计标签时,您只需使用一种方法计算每行总计的数量乘以价格,然后将这些值相加以计算总计。然后它将相应地更新总计文本字段:

    private extension ViewController {
        func updateTotal() {
            let total = items
                .map { $0.quantity * $0.unitPrice }
                .reduce(0, +)
    
            totalLabel.text = totalFormatter.string(for: total)
        }
    }
    

    请注意,我不是从单元格中检索这些数字(因为它们可能会被重复使用),而是从模型中检索我需要的所有数据。

  4. 但是,这里的关键是,例如,如果您的单元格允许用户更改其中一个值,那么您需要一种机制来更新表视图控制器的模型。我们将为此使用一个协议:

    protocol ItemCellDelegate: class {
        func cell(_ cell: ItemCell, didUpdateQuantity quantity: Decimal)
    }
    
    class ItemCell: UITableViewCell {
        @IBOutlet weak var nameLabel: UILabel!
        @IBOutlet weak var quantityTextField: UITextField!
        @IBOutlet weak var unitPriceLabel: UILabel!
    
        static let quantityFormatter: NumberFormatter = ...
        static let priceFormatter: NumberFormatter = ...
    
        weak var delegate: ItemCellDelegate?
    }
    

    显然,当您配置单元格时,视图控制器将指定更新文本字段(或其他)的委托:

    // MARK: Public methods
    
    extension ItemCell {
        func configure(name: String, quantity: Decimal, unitPrice: Decimal, delegate: ItemCellDelegate) {
            self.delegate = delegate
    
            nameLabel.text = name
            quantityTextField.text = ItemCell.quantityFormatter.string(for: quantity)
            unitPriceLabel.text = ItemCell.priceFormatter.string(for: unitPrice)
        }
    }
    

    ItemCell获取更新时,它只是调用委托:

    // MARK: Private methods
    
    private extension ItemCell {
        @IBAction func didUpdateQuantity(_ sender: UITextField) {
            var quantity: Decimal?
    
            if let text = sender.text, let value = ItemCell.quantityFormatter.number(from: text) {
                quantity = value.decimalValue
            }
    
            delegate?.cell(self, didUpdateQuantity: quantity ?? 0)
        }
    }
    

    然后,当视图控制器配置单元格时,它将自己提供为委托:

    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return items.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell
            let item = items[indexPath.row]
            cell.configure(name: item.name, quantity: item.quantity, unitPrice: item.unitPrice, delegate: self)
            return cell
        }
    }
    

    而且,当然,视图控制器将遵循该协议来接受对文本字段的更新并更新模型:

    extension ViewController: ItemCellDelegate {
        func cell(_ cell: ItemCell, didUpdateQuantity quantity: Decimal) {
            guard let indexPath = tableView.indexPath(for: cell) else { return }
    
            items[indexPath.row].quantity = quantity
    
            updateTotal()
        }
    }
    

    而且,如您所见,如果可以的话,更新模型后,它也可以自动更新总数。

这里的关键是我们从不将单元格用作保存数据的地方。这些单元格仅用于(a)显示数据和(b)通知视图控制器是否需要注意任何更新。

我们努力实现非常清晰的职责分离,其中“视图”用于显示屏幕上的控件并与之交互,“模型”包含我们所有的数据。


推荐阅读