【问题标题】:Label Data lost when scrolling in UITableView在 UITableView 中滚动时标签数据丢失
【发布时间】:2021-07-19 22:13:50
【问题描述】:

我制作了一个带有标签的表格视图,该标签在按下按钮时递增和递减,另一个按钮在 UItableView 之外的另一个标签中显示文本。一切正常,但是当我滚动 Tableview 时,值重置为零!

Before Scrolling After Scrolling

我的 ViewController 类

class ViewController: UIViewController{

var numArray = [Value]()
var initialValue = 0


@IBOutlet weak var tableView : UITableView!
@IBOutlet weak var lblOutput : UILabel!


override func viewDidLoad() {
    super.viewDidLoad()
    for _ in 0 ... 100{
        numArray.append(Value(number: initialValue))
    }
    self.lblOutput.text = "\(initialValue)"

    tableView.delegate = self
    tableView.dataSource = self
    tableView.reloadData()
    
}
}

 extension ViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return numArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",for: indexPath) as? ControllerTableViewCell else{fatalError("Error in creating cells")}

    cell.delegate = self
    cell.data = numArray[indexPath.row]
    cell.lblInput.text = "\(cell.data.number)"
    
    return cell
}
}

extension ViewController : MyTableViewCellDelegate{
  func DidPrint(Data: String) {
    self.lblOutput.text = "\(Data)"
}
}

我的 TableViewCell 类

protocol MyTableViewCellDelegate : AnyObject {
   func DidPrint(Data: String)
 }


class ControllerTableViewCell: UITableViewCell {

weak var delegate : MyTableViewCellDelegate?
var data : Value!

private var counterValue = 0

@IBOutlet var lblInput : UILabel!
@IBOutlet var btnPrint : UIButton!
@IBOutlet var btnPlus : UIButton!
@IBOutlet var btnMinus : UIButton!

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}


@IBAction func DidPressPrint(){
    self.data.number = counterValue
    delegate?.DidPrint(Data: "\(data.number)")
    print(data.number)
}
@IBAction func DidPressPlus(){
    counterValue += 1
    data.number = counterValue
    self.lblInput.text = "\(data.number)"
}
@IBAction func DidPressMinus(){
    if(counterValue > 0){
                counterValue -= 1
                data.number = counterValue
            }
    else{
        counterValue = 0
        data.number = 0
    }
    self.lblInput.text = "\(data.number)"
}


}

我的数据模型

import Foundation

struct Value{
  var number : Int
}

【问题讨论】:

  • 那是因为你没有更新数据源。
  • @ElTomato 你能解释一下吗?

标签: swift xcode uitableview delegates


【解决方案1】:

您的 TableView 的 numberOfRowsInSection 使用 numArray 作为源 (numArray.count),您的 cellForRowAt 函数也是如此,但您的单元格函数正在更新您的“数据”变量。您的“数据”变量在本地定义到您的 tableView 并在每次激活时重置(包括滚动时)。 您需要更新 numArray 或其他一些全局资源以使其工作。这涉及在单元格函数内使用单元格值的 indexpath,这意味着您需要一种方法来引用单元格内的 indexPath。本文解释了如何使用标签或委托,https://fluffy.es/handling-button-tap-inside-uitableviewcell-without-using-tag/

这是使用现有委托的解决方案。

import UIKit
import Foundation

var initialValue = 0
var numArray = Array(repeating: initialValue, count: 100)

class ViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var lblOutput: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

           self.lblOutput.text = "\(initialValue)"

           tableView.delegate = self
           tableView.dataSource = self
           tableView.reloadData()
        // Do any additional setup after loading the view.
    }


}

extension ViewController : UITableViewDelegate,UITableViewDataSource{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",for: indexPath) as? ControllerTableViewCell else{fatalError("Error in creating cells")}
        cell.indexPath = indexPath
        cell.delegate = self
        cell.lblInput.text = String(numArray[indexPath.row])
        return cell
    }
    
  
}

extension ViewController : MyTableViewCellDelegate{
    
    func DidPrint(Data: String) {
        self.lblOutput.text = "\(Data)"
    }
}

protocol MyTableViewCellDelegate : AnyObject {
    func DidPrint(Data: String)
 }


class ControllerTableViewCell: UITableViewCell {

weak var delegate : MyTableViewCellDelegate?
var indexPath : IndexPath? 

private var counterValue = 0

@IBOutlet var lblInput : UILabel!
@IBOutlet var btnPrint : UIButton!
@IBOutlet var btnPlus : UIButton!
@IBOutlet var btnMinus : UIButton!

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}


@IBAction func DidPressPrint(){
    delegate?.DidPrint(Data: "\(numArray[indexPath!.row])")
}
@IBAction func DidPressPlus(){
    numArray[indexPath!.row]  = numArray[indexPath!.row] + 1
    self.lblInput.text = "\(numArray[indexPath!.row])"
}
@IBAction func DidPressMinus(){
    if(numArray[indexPath!.row] > 0){
        numArray[indexPath!.row] = numArray[indexPath!.row] - 1
    }
    else{
        numArray[indexPath!.row] = 0
    }
    self.lblInput.text = "\(numArray[indexPath!.row])"
}

}

【讨论】:

  • 我无法研究如何使用委托更新值。如果可能,请解释这对我有帮助
  • 你快到了。您已经定义了委托,只需在您的数据源 numArray[] 上使用它。请参阅我原始答案中的更新。
  • 感谢您的发布,但我仍然无法访问 TableViewcell 类中的 numArray,并且我在 numArray = array(repeating: initialValue,count:100) 中遇到问题。错误:无法在属性初始化程序中使用实例成员“initialValue”;属性初始化程序在“self”可用之前运行
  • 确保 'var numArray = ' 在你的类之外定义,就像在我的代码中一样。
  • 好的,谢谢!
【解决方案2】:

正如@El Tomato 所建议的,您没有更新数据源,这就是您的更改在滚动时被“遗忘”的原因。

尝试在ViewController 类中移动您的didPressPlusdidPressMinusdidPressPrint,并重新定义您的表视图委托,如下所示。
通过将tag 属性传递给按钮,您可以检索在函数中按下的项目的索引并编辑正确的数据源项目。
同时删除不必要的MyTableViewCellDelegate

class ViewController: UIViewController{

    var numArray = [Value]()
    var initialValue = 0

    @IBOutlet weak var tableView : UITableView!
    @IBOutlet weak var lblOutput : UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        for _ in 0 ... 100 {
            numArray.append(Value(number: initialValue))
        }
        self.lblOutput.text = "\(initialValue)"

        tableView.delegate = self
        tableView.dataSource = self
    }
}

extension ViewController : UITableViewDelegate, UITableViewDataSource 
{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? ControllerTableViewCell else {fatalError("Error in creating cells")}
        let indexItem = indexPath.row
        let valueItem = numArray[indexItem]

        cell.lblInput.text = valueItem.number

        cell.btnMinus.tag = indexItem
        cell.btnMinus.addTarget(self, action: #selector(didPressMinus(_:)), for: .touchUpInside)

        cell.btnPlus.tag = indexItem
        cell.btnPlus.addTarget(self, action: #selector(didPressPlus(_:)), for: .touchUpInside)

        cell.btnPrint.tag = indexItem
        cell.btnPrint.addTarget(self, action: #selector(didPressPrint(_:)), for: .touchUpInside)

        return cell
    }

    @objc private func didPressPlus(_ sender: UIButton) {
        let dataIndex = sender.tag
        if numArray.count < dataIndex { return }

        let numArrayItem = numArray[dataIndex]

        if (numArrayItem.number >= 0) {
            numArray[dataIndex].number -= 1
        } 

        tableView.reloadData()
    }

    @objc private func didPressMinus(_ sender: UIButton) {
        let dataIndex = sender.tag
        if numArray.count < dataIndex { return }

        numArray[dataIndex].number += 1

        tableView.reloadData()
    }

    @objc private func didPressPrint(_ sender: UIButton) {
        let dataIndex = sender.tag
        if numArray.count < dataIndex { return }

        self.lblOutput.text = "\(numArray[dataIndex].number)"
    }
}

要移动ViewController 中的三个方法,您需要从UITableViewCell 类中删除两个对应的IBAction
此外,删除与 ControllerTableViewCell 操作的链接。
这是生成的ControllerTableViewCell

class ControllerTableViewCell: UITableViewCell {

    @IBOutlet var lblInput : UILabel!
    @IBOutlet var btnPrint : UIButton!
    @IBOutlet var btnPlus : UIButton!
    @IBOutlet var btnMinus : UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
    }
}

【讨论】:

  • 感谢您的洞察,但我如何在 ViewController 中移动我的 didPressPlus 和 didPressMinus?你能详细说明一下吗?我是 swift 的新手
  • @ChetanjeevSinghBains 我刚刚编辑了答案并添加了解释,如果您还不清楚,请告诉我。
  • 我在 sender.view?.tag 上收到一个错误(UIButton 没有成员视图)。我该如何解决这个问题?
  • 糟糕,如果参数是UIButton,您可以直接访问tag 属性。尝试使用编辑后的代码。
  • cell.btnMinus.addTarget 正在产生问题。那是正确的形式吗?错误:1)连续的行必须用';'分隔2) 预期的 ')' 来完成 #selector 表达式 3) 预期的表达式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-30
  • 2015-03-11
相关资源
最近更新 更多