Using Nsuserdefaults on Arrays

how to save and read array of array in NSUserdefaults in swift?

The question reads "array of array" but I think most people probably come here just wanting to know how to save an array to UserDefaults. For those people I will add a few common examples.

String array

Save array

let array = ["horse", "cow", "camel", "sheep", "goat"]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedStringArray")

Retrieve array

let defaults = UserDefaults.standard
let myarray = defaults.stringArray(forKey: "SavedStringArray") ?? [String]()

Int array

Save array

let array = [15, 33, 36, 723, 77, 4]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedIntArray")

Retrieve array

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedIntArray") as? [Int] ?? [Int]()

Bool array

Save array

let array = [true, true, false, true, false]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedBoolArray")

Retrieve array

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedBoolArray") as? [Bool] ?? [Bool]()

Date array

Save array

let array = [Date(), Date(), Date(), Date()]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedDateArray")

Retrieve array

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedDateArray") as? [Date] ?? [Date]()

Object array

Custom objects (and consequently arrays of objects) take a little more work to save to UserDefaults. See the following links for how to do it.

  • Save custom objects into NSUserDefaults
  • Docs for saving color to UserDefaults
  • Attempt to set a non-property-list object as an NSUserDefaults

Notes

  • The nil coalescing operator (??) allows you to return the saved array or an empty array without crashing. It means that if the object returns nil, then the value following the ?? operator will be used instead.
  • As you can see, the basic setup was the same for Int, Bool, and Date. I also tested it with Double. As far as I know, anything that you can save in a property list will work like this.

How to use NSUserDefaults to store an array of dictionaries

Swift 3.x

In Swift 3 it has changed so now it needs to be saved as [Any] Any Array and use UserDefaults array(forKey:) method to load it:

let theTasks: [Any] = [["num": 1, "title": "example", "colour": "red"]]
UserDefaults.standard.set(theTasks, forKey: "myTasks")
if let loadedTasks = UserDefaults.standard.array(forKey: "myTasks") as? [[String: Any]] {
print(loadedTasks)
}

var theTasks: [[String: Any]] {
get {
return UserDefaults.standard.array(forKey: "myTasks") as? [[String: Any]] ?? []
}
set {
UserDefaults.standard.set(newValue as [Any], forKey: "myTasks")
}
}


Swift 2.x

You just need to save it as a AnyObject array and use NSUserDefaults method arrayForKey to load it:

let theTasks: [AnyObject] = [["num": 1, "title": "example", "colour": "red"]]
NSUserDefaults.standardUserDefaults().setObject(theTasks, forKey: "myTasks")
if let loadedTasks = NSUserDefaults.standardUserDefaults().arrayForKey("myTasks") as? [[String: AnyObject]] {
print(loadedTasks)
}

You can also create a computed property with a getter and a setter to do all the work behind the scenes for you as follow:

var theTasks: [[String: AnyObject]] {
get {
return NSUserDefaults.standardUserDefaults().arrayForKey("myTasks") as? [[String: AnyObject]] ?? []
}
set {
NSUserDefaults.standardUserDefaults().setObject(newValue as [AnyObject], forKey: "myTasks")
}
}

print(theTasks) // [["title": example, "colour": red, "num": 1]]
theTasks[0]["title"] = "another example"

print(theTasks) // [["title": another example, "colour": red, "num": 1]]

(Swift) Storing and retrieving Array to NSUserDefaults

From your code I see you are storing some array

// Your code
NSUserDefaults.standardUserDefaults().setObject(myArray, forKey: "\(identity.text!)listA")

and retrieving a string

//Your code
let tabledata = NSUserDefaults.standardUserDefaults().stringForKey("\(identity.text!)listA")

There is probably a type mismatch, You store one type and retrieve another type.

While retrieving either use arrayForKey() or objectForKey() see the code below.

let tabledata = NSUserDefaults.standardUserDefaults().arrayForKey("\(identity.text!)listA") 

or

let tabledata = NSUserDefaults.standardUserDefaults().objectForKey("\(identity.text!)listA")

If it is an array I would go with First one.

NSUserDefaults with big array

As per my exprience NSUserDefaults only use for light weight data like some preferences related data you can store in userDefaults.

Also if you store heavy/large data it will slower your app as it will store in single plist file.

And due to heavy data load on app it will create memory issue and as you are working on MacOS you will find memory issue rarely but in term of iOS it will definitely create problem.

I found very good blog of Jeffrey fulton where he define in detail where we needs to use UserDefaults or where not.

Link : UserDefaults Limitations and Alternatives

Also adding to above UserDefault is not safe storage as data can be easily retrievable.

In your case you can use Core Data or SQLIte both are very powerful and easy to use framework for storing data.

Hope this will helps.

Best Practice using an Array of Strings with NSUserDefault

As reading from user defaults could return nil values, use optional binding to be safe:

func getSuggestionData() {
if let suggestionArray = userDefaults.objectForKey("suggestions") {
self.suggestions = suggestionArray
} else {
self.suggestions = [String]()
}
}

But I'd recommend to use an non-optional variable with a defined default value.

In AppDelegate of your app, override init() or insert the code to register the key/value pair.

override init()
{
let defaults = NSUserDefaults.standardUserDefaults()
let defaultValue = ["suggestions" : [String]()];
defaults.registerDefaults(defaultValue)
super.init()
}

Registering the default keys and values is the way Apple suggests in the documentation.

  • If no value is written yet, the default value (empty array) is read.
  • If there is a value, the actual value is read

Instead of the value observer of the variable suggestions implement a method to insert a new value, delete the last one and write the array to disk.
There is no need to use optional binding because the array in user defaults has always a defined state.

let userDefaults = NSUserDefaults.standardUserDefaults()
var suggestions = [String]()

func insertSuggestion(suggestion : String)
{
if suggestions.count == 5 { suggestions.removeLast() }
suggestions.insert(suggestion, atIndex: 0)
userDefaults.setObject(suggestions, forKey: "suggestions")
userDefaults.synchronize()
}

func getSuggestionData() {
suggestions = userDefaults.objectForKey("suggestions") as! [String]
}

override func viewDidLoad() {
super.viewDidLoad()
getSuggestionData()
insertSuggestion("someString")
}

A side note:

never use valueForKey: rather than objectForKey: if you don't need explicitly the key-value-coding method.

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


Related Topics



Leave a reply



Submit