[英]Xcode, Swift - Get row Index of a button whiting a tableViewCell when its clicked
我正在Swift中使用Xcode开发应用程序。 简而言之,我有一个tableViewController可以容纳许多单元格。 每个单元格中都有一个按钮(准确地说是一个步进器)。 我的问题是,如何在每次单击步进器时获取包含步进器的单元格的索引?
*奖励点,用于了解用户是否按下了步进器的“减号”或“加号”侧。
我搜索了很长时间,但仍不确定如何处理这种情况,我尝试的任何方法似乎都没有效果。
一些背景:
我的tableViewController看起来像这样。 在此处输入图片说明
每个单元格都有一些标签,其中填充有从我导入的文件中获取的信息。 导入文件时,我将所有信息存储在一个数组中,每次填充tableView时都会读取该数组。 除此之外,我还有一个将使用步进器递增或递减的标签。 这使我可以跟踪需要订购的物品数量。 最后,我要做的是用要订购的数量更新数组,以便在下次退出并重新打开应用程序时将其保存。
我认为有两种方法可行,
1:使用步进器来触发一个函数,该函数将使用步进器所在单元格的索引值来递增或递减其自身单元格顺序的值。
2:让步进器仅更改orderLabel,然后具有一个保存按钮,该按钮将遍历每个tableCell并读取orderLabel以使用indexValue将其保存到数组中。
我不知道哪种方法是最好的,但是我觉得oderLabel的读取和保存必须在我的ItemTableViewController中进行,因为那是我创建存储所有数据的数组的地方。
谢谢,希望对您有所帮助。
创建带有委托的协议,以实现步进器的减量和增量,然后将委托属性添加到您的单元格中,以便在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
}
将控制器设置为单元的委托人将要求它遵守单元的协议。 您可以创建扩展以包含委托方法并访问表视图。
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
参数,没有返回值),并添加一个连接到步进器的IBAction
。 在动作调用callback
传递步进器的值:
class MyTableViewCell: UITableViewCell {
var callback : ((Double)->())?
@IBAction func stepperChanged(_ sender: UIStepper) {
callback?(sender.value)
}
}
在cellForRowAt
的视图控制器中,为callback
变量分配一个闭包并处理返回的值。 模型项以及索引路径都在闭包中捕获。
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
,将其连接到步进器,而不是callback
属性,声明一个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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.