我正在使用Swift中的Xcode开发一个应用程序。简单地说,我有一个tableViewController,它包含许多单元格。每个单元格中都有一个按钮(确切地说是一个步进器)。我的问题是,每次点击它(步进器)时,如何获得包含步进器的单元的索引?
*了解用户是否按下步进器的“减号”或“加号”一侧的加分点。
我搜索了很长时间,我仍然不确定如何处理这种情况,我尝试的任何东西似乎都没有用。
某些背景信息:
我的tableViewController看起来像这样。 enter image description here
每个单元格都有一些标签,这些标签填充了从我导入的文件中获取的信息。导入文件时,我将其所有信息存储在每次填充tableView时读取的数组中。除此之外,我还有一个使用步进器增加或减少的标签。这允许我跟踪我需要订购多少项目。最后,我想要做的是用我想订购的数量更新我的数组,以便在下次退出并重新打开应用程序时保存它。
我认为有两种方法可行,
1:使用步进器触发一个函数,该函数将使用步进器所在单元格的索引值递增或递减其自身单元格的值。
2:让步进器只更改orderLabel,然后有一个保存按钮,它将遍历每个tableCell并读取orderLabel以使用indexValue将其保存到数组中。
我不知道哪种方法是最好的方法,但我觉得oderLabel的数据读取和保存必须在我的ItemTableViewController中进行,因为那是我创建存储所有数据的数组的地方。
谢谢,我希望这会有所帮助。
答案 0 :(得分:3)
使用委托创建一个协议,用于步进器的递减和递增,然后向您的单元格添加委托属性,以便在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)
}
}
}
答案 1 :(得分:0)
在我看来,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
}