How to store array list of custom objects to NSUserDefaults?
You need to implement protocol NSCoding for your custom class. Please see this Swift example.
Save custom objects into NSUserDefaults
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")
}
}
how can store custom objects in NSUserDefaults
First you create custom class Like below.
CustomObject.h
#import <Foundation/Foundation.h>
@interface CustomObject : NSObject<NSCoding>
@property(strong,nonatomic)NSString *name;
@end
CustomObject.m
#import "CustomObject.h"
@implementation CustomObject
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.name forKey:@"name"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.name = [decoder decodeObjectForKey:@"name"];
}
return self;
}
Then create CustomObject class object and store in NSUserDefaults
Stored your object like this
CustomObject *object =[CustomObject new];
object.name = @"test";
NSMutableArray *arr = [[NSMutableArray alloc]init];
[arr addObject:object];
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:arr];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:encodedObject forKey:@"storeObject"];
[defaults synchronize];
get custom object from NSUserDefaults like this
NSData *storedEncodedObject = [defaults objectForKey:@"storeObject"];
NSArray *arrStoreObject = [NSKeyedUnarchiver unarchiveObjectWithData:storedEncodedObject];
for (int i=0; i<arrStoreObject.count; i++)
{
CustomObject *storedObject = [arrStoreObject objectAtIndex:i];
NSLog(@"%@",storedObject.name);
}
Store Custom Objects in NSUserDefaults
You unarchive incorrect object. You store NSArray to NSUserDefaults
NSArray * archiveArray = [userData objectForKey:@"personDataArray"];
for (NSData *personEncodedObject in archiveArray) {
id personObject = [NSKeyedUnarchiver unarchiveObjectWithData:personEncodedObject];
}
How can I store an array of custom objects (Goals)
I am posting code from a learning project I did to store objects using NSCoding. Fully functional and ready to use. A math game that was storing game variables, etc.
//********This class creates the object and properties to store********
import Foundation
class ButtonStates: NSObject {
var sign: String = "+"
var level: Int = 1
var problems: Int = 10
var time: Int = 30
var skipWrongAnswers = true
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeObject(sign, forKey: "sign")
aCoder.encodeInteger(level, forKey: "level")
aCoder.encodeInteger(problems, forKey: "problems")
aCoder.encodeInteger(time, forKey: "time")
aCoder.encodeBool(skipWrongAnswers, forKey: "skipWrongAnswers")
}
init(coder aDecoder: NSCoder!) {
sign = aDecoder.decodeObjectForKey("sign") as String
level = aDecoder.decodeIntegerForKey("level")
problems = aDecoder.decodeIntegerForKey("problems")
time = aDecoder.decodeIntegerForKey("time")
skipWrongAnswers = aDecoder.decodeBoolForKey("skipWrongAnswers")
}
override init() {
}
}
//********Here is the data archiving and retrieving class********
class ArchiveButtonStates:NSObject {
var documentDirectories:NSArray = []
var documentDirectory:String = ""
var path:String = ""
func ArchiveButtons(#buttonStates: ButtonStates) {
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("buttonStates.archive")
if NSKeyedArchiver.archiveRootObject(buttonStates, toFile: path) {
//println("Success writing to file!")
} else {
println("Unable to write to file!")
}
}
func RetrieveButtons() -> NSObject {
var dataToRetrieve = ButtonStates()
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("buttonStates.archive")
if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? ButtonStates {
dataToRetrieve = dataToRetrieve2 as ButtonStates
}
return(dataToRetrieve)
}
}
the following is in my ViewController where the game is played. Only showing the relevant code for retrieving and storing objects
class mathGame: UIViewController {
var buttonStates = ButtonStates()
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//set inital view
//retrieving a stored object & placing property into local class variables
buttonStates = ArchiveButtonStates().RetrieveButtons() as ButtonStates
gameData.sign = buttonStates.sign
gameData.level = buttonStates.level
gameData.problems = buttonStates.problems
gameData.time = buttonStates.time
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
//storing the object
ArchiveButtonStates().ArchiveButtons(buttonStates: buttonStates)
}
}
Save Custom Class Array With NSUserDefaults
Here is the simple example for you to save and retrive class from NSUserDefaults
:
//your class
class Person: NSObject, NSCoding {
var name: String!
var age: Int!
required convenience init(coder decoder: NSCoder) {
self.init()
self.name = decoder.decodeObjectForKey("name") as! String
self.age = decoder.decodeObjectForKey("age") as! Int
}
convenience init(name: String, age: Int) {
self.init()
self.name = name
self.age = age
}
func encodeWithCoder(coder: NSCoder) {
if let name = name { coder.encodeObject(name, forKey: "name") }
if let age = age { coder.encodeObject(age, forKey: "age") }
}
}
//store values in class and store it to NSUserDefaults
var newPerson = [Person]()
newPerson.append(Person(name: "Leo", age: 45))
newPerson.append(Person(name: "Dharmesh", age: 25))
let personData = NSKeyedArchiver.archivedDataWithRootObject(newPerson)
NSUserDefaults().setObject(personData, forKey: "personData")
//retrive your values
if let loadedData = NSUserDefaults().dataForKey("personData") {
loadedData
if let loadedPerson = NSKeyedUnarchiver.unarchiveObjectWithData(loadedData) as? [Person] {
loadedPerson[0].name //"Leo"
loadedPerson[0].age //45
}
}
Tested with playground.
Hope this example will help.
Storing custom objects in an NSMutableArray in NSUserDefaults
For loading custom objects in an array, this is what I've used to grab the array:
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
objectArray = [[NSMutableArray alloc] init];
}
You should check that the data returned from the user defaults is not nil, because I believe unarchiving from nil causes a crash.
Archiving is simple, using the following code:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];
As f3lix pointed out, you need to make your custom object comply to the NSCoding protocol. Adding methods like the following should do the trick:
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:label forKey:@"label"];
[coder encodeInteger:numberID forKey:@"numberID"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [super init];
if (self != nil)
{
label = [[coder decodeObjectForKey:@"label"] retain];
numberID = [[coder decodeIntegerForKey:@"numberID"] retain];
}
return self;
}
How to use NSUserDefaults to store an array of custom classes in Swift?
Your Person class should look like this:
Swift 3:
class Person : NSObject, NSCoding{
// Person dictionary variable
var name: String?
var age: String?
var html_url: String?
init(json: NSDictionary) { // Dictionary object
self.name = json["name"] as? String
self.age = json["age"] as? String
self.html_url = json["html_url"] as? String // Location of the JSON file
}
required init?(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey("name") as? String;
self.age = aDecoder.decodeObjectForKey("age") as? String;
self.html_url = aDecoder.decodeObjectForKey("html") as? String;
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.name, forKey: "name");
aCoder.encodeObject(self.age, forKey: "age");
aCoder.encodeObject(self.html_url, forKey: "html");
}
}
And here you have an example of saving and retrieving the array from NSUserDefaults:
let p = Person()
p.name = "person1"
p.age = "12"
p.html_url = "www.google.ro"
let p2 = Person()
p2.name = "person2"
p2.age = "11"
p2.html_url = "www.google.ro"
let array = [p, p2]
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(NSKeyedArchiver.archivedDataWithRootObject(array), forKey: "persons")
userDefaults.synchronize()
let array : [Person]
array = NSKeyedUnarchiver.unarchiveObjectWithData(userDefaults.objectForKey("persons") as! NSData) as! [Person]
print("\(array[0].name)\(array[1].name)")
Swift 4:
class Person : NSObject, NSCoding{
// Person dictionary variable
var name: String?
var age: String?
var html_url: String?
init(json: NSDictionary) { // Dictionary object
self.name = json["name"] as? String
self.age = json["age"] as? String
self.html_url = json["html_url"] as? String // Location of the JSON file
}
required init?(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObject(forKey: "name") as? String;
self.age = aDecoder.decodeObject(forKey: "age") as? String;
self.html_url = aDecoder.decodeObject(forKey: "html") as? String;
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.name, forKey: "name");
aCoder.encode(self.age, forKey: "age");
aCoder.encode(self.html_url, forKey: "html");
}
}
How to save NSMutableArray of custom class objects in NSUserDefaults?
First add this in Student
class
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:self.Forename forKey:@"keyForename"];
// do same for all property
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[Student alloc] init];
if (self != nil)
{
self.Forename = [coder decodeObjectForKey:@"keyForename"];
// do same other property here
}
return self;
}
Store Array
[studentArray addObject:student1];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:studentArray] forKey:@"mySavedArray"];
Retrieve Array
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *savedArray = [currentDefaults objectForKey:@"mySavedArray"];
if (savedArray != nil)
{
NSArray *oldArray = [NSKeyedUnarchiver unarchiveObjectWithData:savedArray];
if (oldArray != nil) {
customObjectArray = [[NSMutableArray alloc] initWithArray:oldArray];
} else {
customObjectArray = [[NSMutableArray alloc] init];
}
}
Related Topics
Getting the Local iPhone Number Through Sdk
Why Was Uitextfield's Text Property Changed to an Optional in Swift 2
Makekeywindow VS Makekeyandvisible
How to Add Firebase to Today Extension iOS
Apns Push Notifications Not Working on Production
Cancel Button Is Not Shown in Uisearchbar
Obtaining Bluetooth Le Scan Response Data with iOS
Sprite Kit Sprites Loading Performance Improvement
Game Engine Collison Bitmask... Why 0X01 etc
Swift Unsafemutablepointer<Unmanaged<Cfstring>> Allocation and Print
Removing Lagging Latency in Drawing Uibezierpath Smooth Lines in Swift
Hide a Phone Call Completely in iOS (Jailbreak Device)
Nspredicate Filtered by Year Moth Day
Xcode5 Simulator: Unknown Option Character 'X' In: -Xlinker