Search code examples
iosswiftnsuserdefaults

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

    }

}

Solution

  • 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")
    

    and unarchive it like this

    let decoded  = userDefaults.data(forKey: "teams")
    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")
        }
    }