Save custom objects into NSUserDefaults

IosSwiftNsuserdefaults

Ios Problem Overview


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

    }

}

Ios Solutions


Solution 1 - Ios

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.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")
    }
}

Solution 2 - Ios

You can try NSKeyedUnarchiver, like below

Here i stored UIColor Object in UserDefault You can change it with your object

 NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:colorData forKey:@"myColor"];

and to retrive that

NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:@"myColor"];
UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];

Note : This is Objective C but I hope you can covert this in Swift

Hope this solve your problem


Update : Swift 5

Archive in Swift

do{
    let colorAsData = try NSKeyedArchiver.archivedData(withRootObject: UIColor.red, requiringSecureCoding: true)
    UserDefaults.standard.set(colorAsData, forKey: "myColor")
    UserDefaults.standard.synchronize()
}catch (let error){ 
    #if DEBUG
        print("Failed to convert UIColor to Data : \(error.localizedDescription)")
    #endif
}

Unarchive in Swift

do{
    if let colorAsData = UserDefaults.standard.object(forKey: "myColor") as? Data{
        if let color = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [UIColor.self], from: colorAsData){
            // Use Color
        }
    }
}catch (let error){
    #if DEBUG
        print("Failed to convert UIColor to Data : \(error.localizedDescription)")
    #endif
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter PikView Question on Stackoverflow
Solution 1 - Iosmohamede1945View Answer on Stackoverflow
Solution 2 - IosMalav SoniView Answer on Stackoverflow