如何从自定义单元格中保存 UILabel,以便每次打开应用程序时它都显示最新的更改?

How to save UILabel from custom cell so that every time I open the app it displays the latest change?

我是 Swift 的初学者。我已经用尽了所有的尝试和错误,需要帮助!!

我正在使用 UITableView 创建一个记分牌项目,该项目带有一个包含 UILabel 和 UIButton 的自定义单元格。按下按钮后,UILabel 递增 1 以模拟玩家的一个点。我无法在 UILabel 中保存该点,因此每次我打开该应用程序时,该播放器的点仍然存在。我试过使用 UserDefaults、结构和委托,但没有任何运气......我可能做错了。我只需要知道正确的方法是什么。

注意:我能够从 UIAlertController 中成功保存播放器名称,这样当我打开应用程序时名称仍然存在,除非我删除它们,但没有运气保存每个名称本身的分数,它们仍然是“0”。

当我关闭然后打开应用程序时它应该是这样的,但只有当应用程序打开时它才会这样:

Scoreboard UITableView - Screenshot

这是 ViewController 代码:

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var items = [String]()

    @IBOutlet weak var listTableView: UITableView!
    @IBAction func addItem(_ sender: AnyObject) {
        alert()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        listTableView.dataSource = self
        self.items = UserDefaults.standard.stringArray(forKey:"items")  ?? [String]()
    }

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

        cell.textLabel?.text = items[indexPath.row]

        return cell
    }


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

    func saveData() {
        UserDefaults.standard.set(items, forKey: "items")
    }

    func alert(){
        let alert = UIAlertController(title: "Add Player", message: "", preferredStyle: .alert)
        alert.addTextField{
            (textfield) in
            textfield.placeholder = " Enter Player Name "

        }
        let add = UIAlertAction(title: "Add", style: .default)
            {

            (action) in guard let textfield = alert.textFields?.first else {return}

            if let newText = textfield.text
            {
                self.items.append(newText)
                self.saveData()
                let indexPath = IndexPath(row: self.items.count - 1, section: 0)
                self.listTableView.insertRows(at: [indexPath], with: .automatic)
            }
        }

        let cancel = UIAlertAction(title: "Cancel", style: .cancel) {
            (alert) in

        }

        alert.addAction(add)
        alert.addAction(cancel)

        present(alert, animated: true, completion: nil)

    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        items.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .automatic)
        saveData()

    }

}

这是我的自定义单元格代码,名为 PointsCell:

import UIKit

class PointsCell: UITableViewCell {

    var winScore = 0
    @IBOutlet weak var scoreUILabel: UILabel!

   @IBAction func pointButtonPressed(_ sender: Any) {
        winScore += 1
        scoreUILabel.text = "\(winScore)"

    }

}

分数仍然为 0,因为您正在保存它们,首先您需要为每个玩家分配分数,因此您需要将玩家名称和分数组合到对象中。

class Player:NSObject, Codable{
    let name: String
    var score : Int
    init(name: String, score: Int) {
        self.name = name
        self.score = score
    }
    override var description: String{
        return "Name :" + self.name + " Score :" + String(self.score )
    }
}

Swift 4 介绍了 Codable 协议,通过在您自己的类型上采用 Codable,您可以将它们序列化为任何内置数据格式。

现在您可以轻松访问带有姓名和分数的球员。

var players = [Player]()

UserDefaults中获取储值

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let items: Data = UserDefaults.standard.object(forKey: "items") as? Data{
            self.players = try! PropertyListDecoder().decode([Player].self, from: items)
            self.listTableView.reloadData()
        }
    }

当您将新玩家添加到您的列表时,创建 Player 的新实例并将其添加到列表。

func alert(){
    let alert = UIAlertController(title: "Add Player", message: "", preferredStyle: .alert)
    alert.addTextField{
        (textfield) in
        textfield.placeholder = " Enter Player Name "

    }
    let add = UIAlertAction(title: "Add", style: .default)
    {
        (action) in guard let textfield = alert.textFields?.first else {return}
        if let newText = textfield.text
        {
            let player = Player(name: newText, score: 0)
            self.players.append(player)
            let indexPath = IndexPath(row: self.players.count - 1, section: 0)
            self.listTableView.insertRows(at: [indexPath], with: .automatic)
        }
    }

    let cancel = UIAlertAction(title: "Cancel", style: .cancel) {
        (alert) in

    }
    alert.addAction(add)
    alert.addAction(cancel)
    present(alert, animated: true, completion: nil)

}

现在将您的 UITableViewDataSource 方法更新为新列表项。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! PointsCell
    cell.player = players[indexPath.row]
    return cell
}

现在需要更新 saveData 方法以将新列表保存到 UserDefaults 中,您可以在需要保存列表时调用此方法。

func saveData() {
    UserDefaults.standard.set(try! PropertyListEncoder().encode(self.players), forKey: "items")
}

PointsCell class 也需要更新为新的对象类型:

class PointsCell: UITableViewCell {
    @IBOutlet weak var scoreUILabel: UILabel!
    @IBOutlet weak var nameUILabel: UILabel!

    var player: Player? {
        didSet{
            if let name = player?.name {
                self.nameUILabel?.text = name
            }
            if let score = player?.score {
                self.scoreUILabel?.text = String(score)
            }
        }
    }

    @IBAction func pointbuttonPressed(_ sender: Any) {
        if self.player != nil{
            let score = self.player?.score ?? 0
            self.player?.score = score + 1
            scoreUILabel.text = String(self.player?.score ?? 0)
        }
    }
}