switch in a tableview with UserDefaults, several is activated by itself

Switch in a tableview with UserDefaults, several is activated by itself

有问题,我解释。

我想激活一个 Switch,可以在 tableView 中打开应用程序。

为此,我将标签保存在 NSUserDefault 中,如果打开应用程序,标签在 NSUserDefault 中,它会激活开关。

问题是,在下面的图片中,我只是打开了开关 A 和 B,但是当我滚动时,其他开关激活为 q、s、c,但从不相同。

你有什么想法可以建议我吗? 我但我的代码在控制台下面。

Screen 1

Screen 2

ViewController :

@IBOutlet weak var tableView_t: UITableView!

let station = ["A","B","C","D","E","F","G","H","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","&","é","("]

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? TableViewCell

    cell?.configCell(station[indexPath.item])

    return cell!
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
    return station.count
}

表格视图单元格:

@IBOutlet weak var switch_t: UISwitch!
@IBOutlet weak var label_t: UILabel!

func configCell(_ labels : String)
{
    label_t.text = labels

    if let sav = UserDefaults.standard.value(forKey: "switch") as? [String]
    {
        print(sav)
        for switchs in sav
        {
            print(switchs)
            if switchs == labels
            {
                switch_t.setOn(true, animated: false)
                print("On")
            }
        }
     }
}

@IBAction func actionSwitch(_ sender: Any)
{
    var sav : [String] = []

    if let saving = UserDefaults.standard.value(forKey: "switch") as? [String]
    {
        sav = saving
    }

    if switch_t.isOn
    {
        sav.append(label_t.text!)
        UserDefaults.standard.set(sav, forKey: "switch")
        print(sav)
    }
    else
    {
        var number = 0

        for s in sav
        {
            if s == label_t.text
            {
                sav.remove(at: number)
                UserDefaults.standard.set(sav, forKey: "switch")
            }
            number += 1
            print(sav)
        }
    }

}  

控制台:

["A", "B"] A On B ["A", "B"] A B On ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B ["A", "B"] A B

细胞得到重复利用。您必须始终为每个条件设置单元格的属性,以便为每个索引路径完全设置单元格。您的代码只处理打开单元格的开关,而不是关闭。

有两种解决方法。

  1. 更新您的 configCell 方法以在任何不应打开的情况下关闭开关。
  2. 覆盖单元格的 prepareForReuse 方法。在这种方法中,您应该重置单元格的所有状态。这包括将开关设置为关闭并清除标签的文本。

附带说明一下,您的代码还有其他几个小问题需要清理。

  1. 不要将键值编码与 UserDefaults 一起使用,除非您清楚地知道需要这样做。使用正确的方法保存和读取 UserDefaults.
  2. 中的值
  3. 在您的 cellForRowAt 中,您应该将单元格强制转换为所需的类型。这使得该方法中的其余代码更易于编写,如果转换错误,您希望应用程序快速崩溃,因为这意味着您有需要修复的编程错误。
  4. Minor - 你的 configCell 方法的参数被称为 labels 但它只 repents 一个标签。给它一个复数名称会让人感到困惑。
  5. 您检查单元格开关是否应该打开的逻辑比需要的复杂得多。使用Array.
  6. contains方法
  7. 您的更新代码 UserDefaults 比需要的更复杂。
  8. 您引用的是 IndexPathitem 属性。这意味着与 UICollectionView 一起使用。对于 UITableView,使用 row.

下面是解决上述所有问题后我将如何编写您的代码。

Table 控制器:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell

    cell.configCell(station[indexPath.row])

    return cell
}

小区代码:

func configCell(_ label: String) {
    label_t.text = label

    if let sav = UserDefaults.standard.array(forKey: "switch") as? [String] {
        switch_t.isOn = sav.contains(label)
    } else {
        switch_t.isOn = false
    }
}

@IBAction func actionSwitch(_ sender: UISlider) {
    var labels = (UserDefaults.standard.array(forKey: "switch") as? [String]) ?? []

    if let text = label_t.text {
        if switch_t.isOn {
            labels.append(text)
        } else {
            if let index = labels.indexOf(text) {
                labels.remove(at: index)
            }
        }
        UserDefaults.standard.set(labels, forKey: "switch")
    }
}

因为你从不在UserDefault中设置关闭标签时关闭。请尝试

switch_t.setOn(false, animated: false)

在适当的地方。

你需要弄清楚 iOS 不会为每一行创建新的单元格,它只是一次又一次地重复使用 1 个单元格,确保你的开关在显示下一个单元格之前打开或关闭,否则相同的状态会适用于其他..在你的情况下,你永远不会在单元格即将显示时关闭开关

switch_t.setOn(false, animated: true)