Nsuser по умолчанию-сохранение 3 переменных вместе, а затем выборка

Я использую NSUserDefaultsпостоянное хранилище в своем приложении. Это игра, где после окончания игры счет, вместе с датой и именем (введенным пользователем) должны быть сохранены, а затем показаны в виде таблицы. Мой код до сих пор:

import UIKit

class LeaderboardVC: UIViewController, UITableViewDataSource, UITableViewDelegate {

var finishedGame = 0
var gameScore:Int! = 0
var name:String!
var date:String!
var score:Int!
var scoreData = [NSArray]()
var defaults = UserDefaults.standard

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    if finishedGame == 1{
        saveNew()
    }

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


}

override func viewWillAppear(_ animated: Bool) {

    self.navigationController?.isNavigationBarHidden = false
    self.navigationItem.hidesBackButton = true



}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

func saveNew() {

    let enterNameAlert = UIAlertController(title: "Please Enter Your Name", message: "This will be used to place you in the leaderboards", preferredStyle: .alert)

    enterNameAlert.addTextField { (textField:UITextField) -> Void in
        textField.placeholder = "Name"
        textField.autocapitalizationType = UITextAutocapitalizationType.words
        textField.autocorrectionType = UITextAutocorrectionType.no
        textField.clearsOnBeginEditing = true
        textField.clearsOnInsertion = true
        textField.clearButtonMode = UITextFieldViewMode.always
        textField.keyboardType = UIKeyboardType.default

    }
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

    let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (action:UIAlertAction) in

        let currentTime = Date()
        let timeFormatter = DateFormatter()
        timeFormatter.locale = Locale.current
        timeFormatter.dateFormat = "HH:mm dd/MM/yy"
        let convertedTime = timeFormatter.string(from: currentTime) //date
        let enteredName = enterNameAlert.textFields?.first?.text //name

        // set object of date,name and score here
    }

    enterNameAlert.addAction(cancelAction)
    enterNameAlert.addAction(confirmAction)
    self.present(enterNameAlert, animated: true, completion: nil)

}

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

    cell.dateLabel?.text =
    cell.dateLabel.adjustsFontSizeToFitWidth = true
    cell.scoreLabel?.text =
    cell.scoreLabel.adjustsFontSizeToFitWidth = true
    cell.nameLabel?.text =
    cell.nameLabel.adjustsFontSizeToFitWidth = true

    return cell
}

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

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}
}

В ячейке есть 3 метки по одной для каждого из 3 значений, которые должны быть отображены. Как установить эти значения NSUserDefaults(они должны быть вместе, например score: 500 идет с именем: John и так далее)?

EDIT-НОВЫЙ КОД

import UIKit

класс LeaderboardVC: UIViewController, UITableViewDataSource, UITableViewDelegate {

var finishedGame = 0
var gameScore:Int! = 0
var defaults = UserDefaults.standard
var newUserArray = NSMutableArray()

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    if finishedGame == 1{
        saveNew()
    }

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


}

override func viewWillAppear(_ animated: Bool) {

    self.navigationController?.isNavigationBarHidden = false
    self.navigationItem.hidesBackButton = true



}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

func saveNew() {

    let enterNameAlert = UIAlertController(title: "Please Enter Your Name", message: "This will be used to place you in the leaderboards", preferredStyle: .alert)

    enterNameAlert.addTextField { (textField:UITextField) -> Void in
        textField.placeholder = "Name"
        textField.autocapitalizationType = UITextAutocapitalizationType.words
        textField.autocorrectionType = UITextAutocorrectionType.no
        textField.clearsOnBeginEditing = true
        textField.clearsOnInsertion = true
        textField.clearButtonMode = UITextFieldViewMode.always
        textField.keyboardType = UIKeyboardType.default

    }
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

    let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (action:UIAlertAction) in

        let currentTime = Date()
        let timeFormatter = DateFormatter()
        timeFormatter.locale = Locale.current
        timeFormatter.dateFormat = "HH:mm dd/MM/yy"
        let convertedTime = timeFormatter.string(from: currentTime)
        let enteredName = enterNameAlert.textFields?.first?.text

        let newUserData = self.defaults.object(forKey: "UserData") as! NSArray
        let newUserArray = NSMutableArray(array: newUserData)

        let newUserRecord = [
            "Name"  : enteredName!,
            "Score" : String(self.gameScore),
            "Date"    : convertedTime
            ] as [String : String]

        newUserArray.add(newUserRecord)
        self.defaults.set(newUserArray, forKey: "UserData")
        self.defaults.synchronize()
        print(newUserArray)
        print("hello")
        print(self.defaults)


    }

    enterNameAlert.addAction(cancelAction)
    enterNameAlert.addAction(confirmAction)
    self.present(enterNameAlert, animated: true, completion: nil)

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! LeaderBoardCell
    let userData = defaults.object(forKey: "UserData") as! NSArray

    cell.dateLabel?.text = "Date: (((userData.object(at: indexPath.row) as! [String:Any])["Date"] as! String))"
    cell.dateLabel.adjustsFontSizeToFitWidth = true
    cell.scoreLabel?.text = "Score: (((userData.object(at: indexPath.row) as! [String:Any])["Score"] as! String))"
    cell.scoreLabel.adjustsFontSizeToFitWidth = true
    cell.nameLabel?.text = "Name: (((userData.object(at: indexPath.row) as! [String:Any])["Name"] as! String))"
    cell.nameLabel.adjustsFontSizeToFitWidth = true

    return cell
}

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

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

}

2 ответа

  1. Словарь можно установить в UserDefaults (это для 3 значений одновременно). Чтобы сделать таблицу лидеров, вам нужно будет держать эти словари в массиве.

    let scoreDict: [String : Any] = ["name": "John", "score": 500, "date": NSDate()]
    let defaults = UserDefaults.standard
    
    let scoresKey = "scores"
    
    var currentScores: [Any] = defaults.array(forKey: scoresKey) ?? []
    currentScores.append(scoreDict)
    
    defaults.set(currentScores, forKey: scoresKey)
    defaults.synchronize()
    
  2. Я не мог получить так много, но я просто обнаружил, что вам нужно добавить некоторые элементы к вашему scoreDataисточнику данных for the tableview

    Здесь вы можете добавить полный объект в UserDefaults

    //Make your scoreData as MutableArray
    var scoreData = NSMutableArray()
    
    // Record of a user
    let user = [
                "name"  : "John",
                "score" : 10,
                "id"    : 20
            ] as [String : Any]
    
    scoreData.add(user)
    defaults.set(scoreData, forKey: "UserData")
    

    Как получить их

    let userData = defaults.object(forKey: "UserData") as! NSArray
    print((userData.object(at: 0) as! [String:Any])["name"] as! String)
    print((userData.object(at: 0) as! [String:Any])["score"] as! Int)
    print((userData.object(at: 0) as! [String:Any])["id"] as! Int)
    

    Я напечатал их на консоли и только 0-й индекс. Вы можете распечатать их на этикетке с indexPath.rowэлементами.

    Редактировать
    Для добавления новой записи сначала извлеките старые данные из userDefaults

    let newUserData = defaults.object(forKey: "UserData") as! NSArray
    

    Затем преобразуйте его в изменяемый массив, так как мы хотим добавить новую запись пользователя. Я мог бы сделать это во время извлечения, но при извлечении из UserDefaultsнего дает неизменяемый объект независимо от того, к чему мы вводим приведение NSMutableArray. Таким образом, преобразовать newUserDataв изменяемый объект

    let newUserMutableArray = NSMutableArray(array: newUserData)
    

    Добавление новой записи

    // New record
    let newUserRecord = [
        "name"  : "Rajan",
        "score" : 20,
        "id"    : 30
        ] as [String : Any]
    
    newUserMutableArray.add(newUserRecord)
    

    Сохраните его снова

    defaults.set(newUserMutableArray, forKey: "UserData")
    

    И снова приведем способ, упомянутый выше. Теперь выборка NSArrayбудет содержать два элемента.
    Я по-прежнему предпочитаю использовать основные данные в этом случае, поскольку обработка станет намного проще.

    Редактировать
    После выборки

    scoreDataArray = defaults.object(forKey: "UserData") as! NSArray
    

    Перезагрузите стол

    self.yourTableView.reloadData()
    

    Ваши методы источника данных представления таблицы будут подобны

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

    В cellForRowAtметоде datasource

    cell.scoreLabel?.text = scoreDataArray.object(at: indexPath.row) as! [String:Any])["score"] as! String