Xcode、Swift - 获取单击时显示 tableViewCell 的按钮的行索引

Xcode, Swift - Get row Index of a button whiting a tableViewCell when its clicked

我正在 Swift 中使用 Xcode 开发应用程序。简而言之,我有一个包含许多单元格的 tableViewController。每个单元格中都有一个按钮(准确地说是一个步进器)。我的问题是,每次单击步进器(步进器)时,如何获取包含步进器的单元格的索引?

*了解用户是否按下了步进器的 'Minus' 或 'Plus' 侧的加分点。

我搜索了很长时间,我仍然不确定如何处理这种情况,我尝试的任何方法似乎都没有用。

一些上下文:

我的 tableViewController 看起来像这样。 enter image description here

每个单元格都有一些标签,其中填充了从我导入的文件中获取的信息。导入文件时,我将其所有信息存储在一个数组中,每次填充 tableView 时都会读取该数组。除此之外,我还有一个标签,可以使用步进器递增或递减。这使我能够跟踪我需要订购的商品的数量。最后,我想做的是用我想要订购的数量更新我的数组,以便在我下次退出并重新打开应用程序时保存它。

我认为有两种方法可行,

1:使用步进器触发一个函数,该函数将使用步进器所在单元格的索引值递增或递减其自身单元格顺序的值。

2:让步进器只更改 orderLabel,然后有一个保存按钮,它将遍历每个 tableCell 并读取 orderLabel 以使用 indexValue 将其保存到数组中。

我不知道哪个是最好的方法,但我觉得必须在我的 ItemTableViewController 中读取 oderLabel 并将其保存到数组中,因为这是我创建存储我所有的数组的地方数据.

谢谢,我希望这会有所帮助。

为步进器的递减和递增创建一个带有委托的协议,然后将委托 属性 添加到您的单元格中,以便在 cellForRowAt 方法中进行设置。

protocol TableViewCellDelegate {
    func tableViewCell(_ cell: TableViewCell, didDecrementStepper: UIStepper)
    func tableViewCell(_ cell: TableViewCell, didIncrementStepper: UIStepper)
}

允许我们决定调用哪个委托方法的额外部分是私有 stepperValue。由于我们使用自己的 属性 跟踪步进器值,因此我们可以从不同的设置事件中受益。

class TableViewCell: UITableViewCell {

    // MARK: Outlets

    @IBOutlet private weak var stepper: UIStepper!

    // MARK: Properties

    weak var delegate: TableViewCellDelegate?

    private(set) var stepperValue: Double = 0 {
        didSet {
            if oldValue < stepperValue {
                delegate?.tableViewCell(self, didIncrementStepper: stepper)
            } else {
                delegate?.tableViewCell(self, didDecrementStepper: stepper)
            }
        }
    }

    // MARK: Actions

    @IBAction func didStepperValueChanged(_ sender: UIStepper) {

        stepperValue = sender.value
    }
}

我们可以使用 @IBAction 将步进器的值更改事件连接到方法并更新我们的 属性 的值。 didSet 事件使用 oldValue 属性 提供的范围来确定值的走向。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
    cell.delegate = self
    return cell
}

将控制器设置为单元的代表将要求它符合单元的协议。您可以创建一个扩展来包含委托方法并访问 table 视图。

extension TableViewController: TableViewCellDelegate {
    func tableViewCell(_ cell: TableViewCell, didIncrementStepper: UIStepper) {
        if let indexPath = tableView.indexPath(for: cell) {
            print(#function, indexPath)
        }
    }

    func tableViewCell(_ cell: TableViewCell, didDecrementStepper: UIStepper) {
        if let indexPath = tableView.indexPath(for: cell) {
            print(#function, indexPath)
        }
    }
}

在我看来,Swift(同时甚至在 Objective-C)中最有效的方法是回调闭包/块。

实施起来非常容易。好处是:

  • 没有额外的协议。
  • 没有额外的委托方法。
  • 索引路径和模型项直接可用。

UITableViewCell子class中声明一个callback属性带闭包(一个Double参数,没有return值)并添加一个 IBAction 连接到步进器。在动作调用中 callback 传递步进器的值:

class MyTableViewCell: UITableViewCell {

    var callback : ((Double)->())?

    @IBAction func stepperChanged(_ sender: UIStepper) {
        callback?(sender.value)
    }
}

cellForRowAt 的视图控制器中,为 callback 变量分配一个闭包并处理 returned 值。模型项以及索引路径在闭包中被捕获。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyIdentifier", for: indexPath) as! MyTableViewCell
    let item = dataSourceArray[indexPath.row] // get the model item from the data source array
    //  update UI
    cell.callback = { value in
        print(indexPath, value)
        // do something with the new value for example update the model
    }

    return cell
}

在 Swift 4 中有一个更聪明的选择,新的 NSKeyValueObservation class。此解决方案的好处是您可以轻松确定步进器是递增还是递减。

而不是 IBAction 创建一个 IBOutlet,将它连接到步进器而不是 callback 属性 声明一个 属性 类型 NSKeyValueObservation

class MyTableViewCell: UITableViewCell {

    @IBOutlet weak var stepper : UIStepper!
    var observation : NSKeyValueObservation?
}

cellForRowAt中分配观察者并传递选项oldnew。在闭包中比较 oldValuenewValue 以获得方向。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyIdentifier", for: indexPath) as! MyTableViewCell
    let item = dataSourceArray[indexPath.row] // get the model item from the data source array
    //  update UI
    cell.observation = cell.stepper.observe(\.value, options: [.old, .new]) { (stepper, change) in
        let wasIncremented = change.oldValue! < change.newValue!
        print("new value:", change.newValue!, "stepper was incremented:", wasIncremented)
    }        
    return cell
}