如何从自定义单元格中保存 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)
}
}
}
我是 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)
}
}
}