Ios Xcode,Swift-在单击tableViewCell时获取按钮的行索引

Ios Xcode,Swift-在单击tableViewCell时获取按钮的行索引,ios,swift,uitableview,uistepper,Ios,Swift,Uitableview,Uistepper,我正在使用Swift中的Xcode开发一个应用程序。简单地说,我有一个包含许多单元格的tableViewController。每个单元中都有一个按钮(确切地说是一个步进器)。我的问题是,每次我点击步进器(步进器)时,我如何获得容纳步进器的单元格的索引 *知道用户是否按下步进器的“负”或“正”侧的额外点数 我搜索了很长一段时间,我仍然不知道如何处理这种情况,我尝试的似乎没有任何效果 一些背景: 我的tableViewController看起来像这样。 每个单元格都有一些标签,这些标签由从我导入的

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

*知道用户是否按下步进器的“负”或“正”侧的额外点数

我搜索了很长一段时间,我仍然不知道如何处理这种情况,我尝试的似乎没有任何效果

一些背景:

我的tableViewController看起来像这样。

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

我认为有两种方法可能有效

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

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

我不知道哪种方法是最好的,但我觉得必须在我的ItemTableViewController中读取和保存oderLabel到数组中,因为在那里我创建了存储所有数据的数组


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

创建一个协议,其中包含用于步进器递减和递增的委托,然后将委托属性添加到单元格中,以便在
cellForRowAt
方法中设置

protocol TableViewCellDelegate {
    func tableViewCell(_ cell: TableViewCell, didDecrementStepper: UIStepper)
    func tableViewCell(_ cell: TableViewCell, didIncrementStepper: UIStepper)
}
允许我们决定调用哪个委托方法的额外部分是private
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
    }
}
将控制器设置为单元的代理将要求它符合单元的协议。您可以创建一个扩展来包含委托方法并访问表视图

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
子类中,声明一个带有闭包的
callback
属性(一个
Double
参数,没有返回值),并添加一个连接到步进器的
iAction
。在动作调用
回调中
传递步进器的值:

class MyTableViewCell: UITableViewCell {

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

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

cellForRowAt
中的视图控制器中,为
回调
变量指定一个闭包,并处理返回值。在闭包中捕获模型项和索引路径

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
类。此解决方案的好处是,您可以轻松确定步进器是递增还是递减

不要使用
IBAction
创建
IBOutlet
,而是将其连接到步进器,并声明类型为
NSKeyValueObservation

class MyTableViewCell: UITableViewCell {

    @IBOutlet weak var stepper : UIStepper!
    var observation : NSKeyValueObservation?
}
cellForRowAt
中分配观察者并传递选项
old
new
。在闭包中,将
oldValue
newValue
进行比较,以获得方向

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
}
func tableView(tableView:UITableView,cellForRowAt indexath:indexPath)->UITableViewCell{
让cell=tableView.dequeueReusableCell(标识符为:“MyIdentifier”,for:indexPath)作为!MyTableViewCell
让item=dataSourceArray[indexPath.row]//从数据源数组中获取模型项
//更新用户界面
cell.observation=cell.stepper.observation(\.value,选项:[.old,.new]){(stepper,change)in
让wasIncremented=change.oldValue!
你能分享你的课程的代码吗?我详细介绍了我的问题是什么以及我正在尝试做什么,我希望这能有所帮助。如果需要,我可以稍后添加代码,但我现在可以访问我的计算机。单元格不应该知道其索引路径或表视图。从单元格和委托协议中删除这些内容。单元格只需将自身传递给委托即可。然后,代理可以对单元格执行它所需的操作。到目前为止,我最喜欢您的选项,使用此方法,您如何判断步进器是递增还是递减?感谢实际上步进器的旧值应该存储在数据模型中,以便您可以比较这两个值以获得方向,但是我用一个智能的替代方法更新了答案,以检测闭包中的步进方向。太棒了,我能够使用NSKeyValueObservation来做我想做的事情。它工作得很好,并且很容易理解您编写的代码是如何工作的。非常感谢。
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
}