在表格视图单元格中使用步进器 - 但返回 VC 的数据未正确更新

Posted

技术标签:

【中文标题】在表格视图单元格中使用步进器 - 但返回 VC 的数据未正确更新【英文标题】:Using a stepper in a table view cell - but the data returning to the VC is not updating correctly 【发布时间】:2016-10-18 10:15:02 【问题描述】:

我正在尝试创建一个配置屏幕,以便用户可以设置他或她想要进行的锻炼次数。我设法将一个表格视图添加到一个空白视图控制器,但存在一些风格限制 - 例如根据单元格的数量展开和折叠表格视图。

所以我想我会在tableviewcontroller 中设置屏幕。现在一切顺利,直到我希望我的 Steppersection 0cell 1 中增加和减少section 1 中的行数。它的工作原理是数据数组(workouts[])用最新的值(在cellForRowAt:indexPath 方法中)更新视图控制器,这反过来用(假定的)最新的workouts.count 更新 numberOfRowsInSection。

但是,事实证明workouts.count 在步进器最后更新数组之前保存了计数。

现在,我尝试了多种解决方法,但我仍然无法正确更新 numberOfRowsInSection 方法 - 在我看来,Workouts 数组没有在 View Controller 中更新为最新值,而是之前的设定值。

这是我的视图控制器:

class AViewController: UITableViewController 

//MARK: Properties
@IBOutlet weak var aTableView: UITableView!

var sections: [String] = ["", "Set Up Circuits"]
var workouts: [Exercise] = []

//MARK: Initialisation
override func viewDidLoad() 
    super.viewDidLoad()
    workouts = [Exercise(name: "Circuit 1", timeMinutes: 2)]
    self.tableView.delegate = self
    self.tableView.dataSource = self


//MARK: Table Config
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
    return self.sections[section]


override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
    switch section 
    case 0:
        return 0.1
    default:
        return 32.0
    


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    switch indexPath.section 
    case 0:
        return 60
    default:
        return 44
    


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

    var numberOfRowsInSection: Int = 0

    switch section 
    case 0:
        numberOfRowsInSection = 1
    default:
        numberOfRowsInSection = workouts.count
        //numberOfRowsInSection = 1
    
    print(numberOfRowsInSection, "number of rows in section", section)
    return numberOfRowsInSection


//MARK: Table Protocols
override func numberOfSections(in tableView: UITableView) -> Int 
    return sections.count


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    switch indexPath.section 

    //Setting layout for circuit number config
    case 0:
        let cell = aTableView.dequeueReusableCell(withIdentifier: "ACircuitTableViewCell") as! ACircuitTableViewCell
        cell.tableView = self.aTableView
        self.workouts = cell.workouts
        print(workouts.count, " VC workouts array count")
        return cell

    //Setting layout for circuit cells
    default:
        let cell = aTableView.dequeueReusableCell(withIdentifier: "ATableViewCell") as! ATableViewCell
        cell.aLabel.text = workouts[indexPath.row].getName()
        cell.aDetail.text = "Tap here to configure"
        return cell

    

这是我的 ACircuitTableViewCell:

class ACircuitTableViewCell: UITableViewCell 

//MARK: Properties
@IBOutlet weak var circuitNumber: UILabel!
@IBOutlet weak var circuitLabel: UILabel!
@IBOutlet weak var circStepper: UIStepper!


var tableView: UITableView!
// var updateCallback : ((_ updateList: Bool)-> Void)?

//var exercises: [Exercise]?
var anArray: [Exercise] = []
var workouts: [Exercise] = [Exercise(name: "Circuit 1", timeMinutes: 2)]

var workoutsCount: Int = 1
var indexPath: NSIndexPath = NSIndexPath(row: 0, section: 1)
//MARK: Original Functions
override func awakeFromNib() 
    super.awakeFromNib()
    // Initialization code

    circuitNumber.text = String(workouts.count)


override func setSelected(_ selected: Bool, animated: Bool) 
    super.setSelected(selected, animated: animated)


@IBAction func valueChanged(_ sender: AnyObject) 
    print("Method .valueChanged activated")

    //Update circuitNumber label
    circuitNumber.text = String(Int(circStepper.value))

    //View pre-array-update status of variables
    print(workouts.count, "anArray before appending")
    print(circStepper.value, "stepper value before appending")
    print(circuitNumber.text, "circuitNumber")

    //Update workouts array
    if workouts.count < Int(circStepper.value) 
        workouts.append(Exercise(name: "Circuit \(Int(circStepper.value))", timeMinutes: 2))
        print(workouts.count, "after appending")

        tableView.reloadData()

       print(workouts.count, "new workout.count")
    


    print(workouts.count, "workouts.count")
    print("Method .valueChanged completed")


这是从应用加载到点击步进器 + 按钮三下到控制台的输出。

1 number of rows in section 1
1 number of rows in section 0
1 number of rows in section 1
1 number of rows in section 0
1 number of rows in section 1
1 number of rows in section 0
1  VC workouts array count
Method .valueChanged activated
1 anArray before appending
2.0 stepper value before appending
Optional("2") circuitNumber
2 after appending
1 number of rows in section 1
1 number of rows in section 0
2 new workout.count
2 workouts.count
Method .valueChanged completed
2  VC workouts array count
Method .valueChanged activated
2 anArray before appending
3.0 stepper value before appending
Optional("3") circuitNumber
3 after appending
2 number of rows in section 1
1 number of rows in section 0
3 new workout.count
3 workouts.count
Method .valueChanged completed
3  VC workouts array count
Method .valueChanged activated
3 anArray before appending
4.0 stepper value before appending
Optional("4") circuitNumber
4 after appending
3 number of rows in section 1
1 number of rows in section 0
4 new workout.count
4 workouts.count
Method .valueChanged completed
4  VC workouts array count
Method .valueChanged activated
4 anArray before appending
5.0 stepper value before appending
Optional("5") circuitNumber
5 after appending
4 number of rows in section 1
1 number of rows in section 0
5 new workout.count
5 workouts.count
Method .valueChanged completed
5  VC workouts array count

【问题讨论】:

请不要将数据源存储在您的单元格(或任何其他视图)中。它打破了 MVC 模式。您应该做的是在控制器中处理步进回调并在那里更改 viewController 的数据源。 @alexburtnik 谢谢!一旦我弄清楚如何在控制器中处理步进回调,表格就会按照我的意愿运行。 不客气。刚刚发布了两种在 viewController 中处理视图事件的常用方法。您可能已经使用过其中之一 【参考方案1】:

您应该在控制器中处理步进回调并在那里更改 viewController 的数据源。

    在视图控制器中处理单元格事件的最常见方法是使用委托,就像我在这里描述的那样: https://***.com/a/40111943/1689376

    或者,您可以在cellForRow 方法中添加带有self 目标的操作:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
    cell.stepper?.tag = indexPath.row
    cell.stepper?.addTarget(self, action: #selector(stepperValueChanged(_:)), for: .valueChanged)
    return cell


func stepperValueChanged(_ stepper: UIStepper) 
    //use stepper.tag as index to fetch an object from your dataSource
    let workout = dataSource[stepper.tag]

【讨论】:

以上是关于在表格视图单元格中使用步进器 - 但返回 VC 的数据未正确更新的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 的表格单元格中显示日期选择器和选择器视图?

自定义表格视图单元格中的 UITextField。点击单元格/文本字段时显示选择器视图

iOS - 如何修复表格视图单元格中的此动画向左然后再次返回

如何从表格视图单元格中获取值

自定义表格单元格中的堆栈视图

在表格视图单元格中使用 UILongPressGestureRecognizer 时出现问题