Как сделать, чтобы UILabel из пользовательского отображения ячейки сохранял изменения в UITableView - PullRequest
0 голосов
/ 04 февраля 2019

Я новичок в Swift.Я исчерпал все свои пробные версии и ошибки и мне нужна помощь !!

Я создаю проект табло, используя UITableView с пользовательской ячейкой, которая содержит UILabel и UIButton.После нажатия кнопки UILabel увеличивается на единицу, чтобы смоделировать точку для игрока.У меня возникают проблемы с сохранением точки в UILabel, чтобы при каждом открытии приложения осталась точка для этого игрока.Я пытался использовать UserDefaults, структуры и делегаты, но мне не повезло ... Я могу сделать это неправильно.Мне просто нужно знать, каков правильный подход для этого.

Примечание: я могу успешно сохранить имя игрока из UIAlertController, чтобы при открытии приложения имена оставались там, пока я их не удалю,но не удалось сохранить очки для каждого имени, они по-прежнему остаются «0».

Это должно выглядеть так, когда я закрываю и открываю приложение, но это происходит только тогда, когда приложениеоткрыто:

Табло UITableView - Снимок экрана

Вот код 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)"

    }

}

1 Ответ

0 голосов
/ 04 февраля 2019

Поскольку ячейки сняты с хранения и хранение данных внутри подкласса ячеек не будет работать, выберите другую стратегию.Ваш массив items должен содержать эту информацию о точках , поэтому для этого вам понадобится ваша пользовательская модель.


Прежде всего, создайте массив из ваших пользовательских моделей.,Эта модель будет содержать заголовок и количество точек элемента

struct Item {
    var title: String
    var points: Int

    init(title: String, points: Int = 0) {
        self.title = title
        self.points = points
    }
}

, затем изменить тип вашего массива на массив Item

var items = [Item]()

Теперь в cellForRowAt установить выходы в зависимостина предмет для индекса

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! PointsCell
    let item = items[indexPath.row]
    cell.textLabel?.text = item.title
    cell.scoreUILabel.text = "\(item.points)"
    return cell
}

Но теперь, как справиться с тем, что пользователь нажимает кнопку в ячейке и как увеличить счет?

Одним из решений является создание переменной закрытия в подклассе UITableViewCell, и когда кнопка будет нажата, это закрытие позволит контроллеру узнать, что кнопка была нажата

class PointsCell: UITableViewCell {

    var buttonPressed: (()->Void)?

    @IBOutlet weak var scoreUILabel: UILabel!

    @IBAction func pointButtonPressed(_ sender: Any) {
        buttonPressed?()
    }

}

, а затем внутри cellForRowAt назначить этои скажите, что если нажата кнопка, увеличьте points этого элемента и перезагрузите эту строку

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! PointsCell
    let item = items[indexPath.row]
    cell.textLabel?.text = item.title
    cell.scoreUILabel.text = "\(item.points)"

    cell.buttonPressed = { // this gets called when `buttonPressed?()` is called from cell class
        self.items[indexPath.row].points += 1
        tableView.reloadRows(at: [indexPath], with: .automatic)
        saveData() // optional
    }

    return cell
}

Обратите внимание, что с этой стратегией вам также нужно будет изменить добавление нового элемента на добавление Item (кстати, вы можете безопасно принудительно развернуть text из UITextField, поскольку это свойство никогда не будет nil)

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

Также обратите внимание, что для сохранения пользовательской модели в UserDefaults вам нужно будет кодировать и декодировать свою пользовательскую модель, поэтому вам нужно будет внедрить Codable в вашу структуру

struct Item: Codable {
    //...
}

, а затем для сохранения использовать JSONEncoder:

func saveData() {
    do {
        let encoded = try JSONEncoder().encode(items)
        UserDefaults.standard.set(encoded, forKey: "items")
    } catch { print(error) }
}

и для извлечения, JSONDecoder:

override func viewDidLoad() {
    super.viewDidLoad()
    listTableView.dataSource = self

    do {
        if let data = UserDefaults.standard.data(forKey:"items") {
            items = try JSONDecoder().decode([Item].self, from: data)
        }
    } catch { print(error) }
}

Последнее замечание на будущее: UserDefaults не предназначены для хранения большого количества данных, и в будущем вы будете программироватьобязательно используйте какую-нибудь базу данных, например Realm илиродной CoreData.

Удачи, кстати!;)

...