Peter Pik Peter Pik - 24 days ago 11
iOS Question

Save custom objects into NSUserDefaults

I'm having a news

ViewController
and a
TeamViewController
. The
TeamViewController
contain a tableView of teamObjects which when selected is added into array. I want to add this array into
NSUserDefaults
so i can access them from the
NewsController
which contain a url request where the teamObjects is needed. However i keep getting:


'Attempt to insert non-property list object (
""
) for key teams'


I'm open for other suggestions if there is better ways than storing it in
NSUserDefaults


didSelectRowAtIndexPath
method

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)


let team = self.teamArray[indexPath.row] as Team
var removed = false

for (index, value) in enumerate(self.teamSelected) {
if (value == team) {
self.teamSelected.removeAtIndex(index)
removed = true
}
}

if (!removed) {
self.teamSelected.append(team)
}

var userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(self.teamSelected, forKey: "teams")
userDefaults.synchronize()

tableView.reloadData()
}


My object

class Team: NSObject{
var id: Int!
var name: NSString!
var shortname: NSString!


init(id: Int, name:NSString, shortname: NSString) {
self.id = id
self.name = name
self.shortname = shortname

}

}

Answer

Actually, you will need to archive the custom object into NSData then save it to user defaults and retrieve it from user defaults and unarchive it again. You can archive it like this

let teams = [Team(id: 1, name: "team1", shortname: "t1"), Team(id: 2, name: "team2", shortname: "t2")]

var userDefaults = UserDefaults.standard
let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: teams)
userDefaults.set(encodedData, forKey: "teams")
userDefaults.synchronize()

and unarchive it like this

let decoded  = userDefaults.object(forKey: "teams") as! Data
let decodedTeams = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! [Team]

But if you just did that you will get

.Team encodeWithCoder:]: unrecognized selector sent to instance

You will have to make Team conform to NSCoding just like this

class Team: NSObject, NSCoding {
    var id: Int!
    var name: String!
    var shortname: String!


    init(id: Int, name: String, shortname: String) {
        self.id = id
        self.name = name
        self.shortname = shortname

    }

    required convenience init(coder aDecoder: NSCoder) {
        let id = aDecoder.decodeInteger(forKey: "id")
        let name = aDecoder.decodeObject(forKey: "name") as! String
        let shortname = aDecoder.decodeObject(forKey: "shortname") as! String
        self.init(id: id, name: name, shortname: shortname)
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(id, forKey: "id")
        aCoder.encode(name, forKey: "name")
        aCoder.encode(shortname, forKey: "shortname")
    }
}
Comments