Coder123
Coder123

Reputation: 854

using NSUserDefaults to save an array of objects


I am new to swift, and I am trying to build a game which will include a top 5 players name and score, if i just add the players to an array and than restart the game it "deletes" the players, so i am trying to use NSUserDefaults(i need to store just 5 strings and 5 integers), it does not work no matter what, the code is:

class scoreController: UITableViewController {

    var playersArray:[Player] = [Player]()

    var nameFromGame = "" //name from game vc
    var timeFromGame = 0 //time from game vc

    let tmpPlayer = Player(playerName: "", scoreTime: 0)
    let playerDefaults = NSUserDefaults.standardUserDefaults()

    override func viewDidLoad() {
        super.viewDidLoad()

        let player1 = Player(playerName: "Bil", scoreTime: 50)
        let player2 = Player(playerName: "Bob", scoreTime: 100)


        playersArray.append(player1)
        playersArray.append(player2)

         tmpPlayer.playerName = nameFromGame
         tmpPlayer.scoreTime = timeFromGame
         playersArray.append(tmpPlayer)

         playerDefaults.setObject(playersArray[11], forKey: "players")

            print(playersArray )
        }
    }

I am just trying to save this for now and it crashes, does anyone know why? and also how can i store this in my app so it will save the data?

thank you!

Upvotes: 0

Views: 69

Answers (3)

NSDavidObject
NSDavidObject

Reputation: 388

Your Player class needs to conform to NSCoding, and you'll need to store an archived data of your players array and unarchive it when extracting out the data.

Class:

class Player: NSObject, NSCoding {
    var playerName: String
    var scoreTime: Int

    init(playerName: String, scoreTime: Int) {
        self.playerName = playerName
        self.scoreTime = scoreTime
    }

    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeInteger(scoreTime, forKey: "score_time")
        aCoder.encodeObject(playerName, forKey: "player_name")
    }

    required convenience init?(coder decoder: NSCoder) {
        guard let playerName = decoder.decodeObjectForKey("player_name") as? String else {
            return nil
        }
        self.init(playerName: playerName, scoreTime: decoder.decodeIntegerForKey("score_time"))
    }
}

NSUserdefaults & Archiving/Unarchiving :

    let player1 = Player(playerName: "Bil", scoreTime: 50)
    let player2 = Player(playerName: "Bob", scoreTime: 100)

    let playersArray = [player1, player2]
    let playersData  = NSKeyedArchiver.archivedDataWithRootObject(playersArray)

    let defaults = NSUserDefaults.standardUserDefaults()
    defaults.setObject(playersData, forKey: "players")
    defaults.synchronize()

    if let playersArrayData = defaults.objectForKey("players") as? NSData {
        let unarchivedPlayers = NSKeyedUnarchiver.unarchiveObjectWithData(playersArrayData) as! [Player]
        print(unarchivedPlayers)
    }

Hope this helps, please remember to choose answer and up-vote if this solves your question.

Upvotes: 1

mginn
mginn

Reputation: 16124

You need to could call

playerDefaults.synchronize()

to save the data in the defaults.

EDIT
As facumenzella says, your other problem is storing custom class objects in the defaults. To solve that you need to implement methods in the custom Player class that tell it how to be converted to data. Then you should serialize the object before you store it in the defaults.

Upvotes: 0

facumenzella
facumenzella

Reputation: 559

Your player objects probably are the problem here. You must implement two methods in your player class (I am no swift master but it's probaby the same mistake):

- (void)encodeWithCoder:(NSCoder *)encoder;
- (id)initWithCoder:(NSCoder *)decoder;

That should work for you. Hope it helps!!

PD: check this answer How to store custom objects in NSUserDefaults

Upvotes: 2

Related Questions