Can't modify array stored in NSUserDefaults - ios

In a class FirstViewController, I add an array with key rentedItems to the NSUserDefaults in the following lines:
let itemArray = [Item]()
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
prefs.setObject(itemArray, forKey: "rentedItems")
Then, in another class SecondViewController, I try
var item: Item?
var prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
func confirmPressed() {
prefs.arrayForKey("rentedItems")?.append(item)
}
This then gives the following error:
Cannot use mutating member on immutable value: function call returns immutable value. I saw a solution in SO here that gave me an idea of the problem, but NSUserDefaults being a default iOS class, I can't use the same solution as there. Any ideas?

You can't directly modify an array from defaults. Instead make a copy, and modify that. You can save that array to defaults afterwards. Simply try like this:
var array = prefs.arrayForKey("rentedItems")?.mutableCopy
array.append(item)

You will need to archive Your Custom Object Array into NSData then save it to NSUserDefaults and retrieve it from NSUserDefaults and unarchive it again. You can archive it like this:
var userDefaults = NSUserDefaults.standardUserDefaults()
let encodedData = NSKeyedArchiver.archivedDataWithRootObject(itemArray)
userDefaults.setObject(encodedData, forKey: "rentedItems")
userDefaults.synchronize()
And unarchive it like this
let decoded = userDefaults.objectForKey("rentedItems") as! NSData
let itemArray = NSKeyedUnarchiver.unarchiveObjectWithData(decoded) as! [Item]

Related

User defaults gives nil value in Swift 3.0

I am new to swift and trying to store NSMutableArray in Userdefaults. Here is what I am doinig :
//to save aaray in user defaults
var set:NSMutableArray = NSMutableArray(objects: self.listId)
self.saveListIdArray(set)
func saveListIdArray(_ params: NSMutableArray = []) {
let defaults = UserDefaults.standard
defaults.set(params, forKey: "ArrayKey")
defaults.synchronize()
}
//to get array from user default
func getUserDefaultKeyForAllObject(key userDefaultsKey: String) -> NSMutableArray {
let array = UserDefaults.standard.object(forKey: NSUserDefaultsKey.LIST_ID_ARRAY) as! NSMutableArray
print(array)
return array
}
App crashes with "fatal error: unexpectedly found nil while unwrapping an Optional value" exception.
Ignore the way I ask the question, help me out here.
Thank you.
Try converting to NSData then storing to nsuserdefaults like below
func saveListIdArray(_ params: NSMutableArray = []) {
let data = NSKeyedArchiver.archivedData(withRootObject: params)
UserDefaults.standard.set(data, forKey: "test")
UserDefaults.standard.synchronize()
}
For retrieving the data use
if let data = UserDefaults.standard.object(forKey: "test") as? Data {
if let storedData = NSKeyedUnarchiver.unarchiveObject(with: data) as? NSMutableArray
{
// In here you can access your array
}
}
You are force unwrapping the NSMutableArray for a key. Don't force unwrap when you try to get the value from a dictionary or UserDefault for a key because there may be a chance that the value does not exist for that key and force unwrapping will crash your app.
Do this as:
//to get array from user default
if let array = UserDefaults.standard.object(forKey:"ArrayKey") as? NSMutableArray
print(array)
}
I have 2 possible reasons for this:
You need to be 100% sure that you are retrieving array with the same key as you save it with. In your code you are saving the array with "ArrayKey" but retrieving it with NSUserDefaultsKey.LIST_ID_ARRAY, are you sure this is the same string?
What datatype is self.listId? If it's a custom class then you need to make that class conform to the nscoding protocol, then encode it to Data and save that to the userDefaults (Save custom objects into NSUserDefaults)
A 3rd reason is that you are trying to get an object from the defaults without ever writing anything to it. Try changing
let array = UserDefaults.standard.object(forKey: NSUserDefaultsKey.LIST_ID_ARRAY) as! NSMutableArray
print(array)
return array
to
if let array = UserDefaults.standard.object(forKey: "ArrayKey") as? NSMutableArray {
print(array)
return array
}
else {
return NSMutableArray()
}

How to remove mutable array element from NSUserdefaults?

I store array element in NSUserdefault and retrive from this but I want to remove array element from NSUserdefault.
retriving from NSuserdefault
let defaults = UserDefaults.standard
let array = defaults.object(forKey: "ArrayString") as? [String] ?? [String]()
print("NSUserDefault :\(array)")
Result:
NSUserDefault :["first", "second","third","fourth","fifth"]
I display this array in CollectionView now I want to remove from this array how?
Thank You in Advance..
We can remove element from NSUserdefault see this...
---> Self Solution and Helpful for me...
Store array in NSUserdefault
let defaults = UserDefaults.standard
defaults.set(appDelegate.arrMutable, forKey: "ArrayString")
defaults.synchronize()
Retrieving from NSUserdefault
var array : Array<String> = []
array = defaults.object(forKey: "ArrayString") as? [String] ?? [String]()
Remove array element from NSUserdefault
array.remove(at: buttonIndex)
defaults.set(array, forKey: "SavedStringArray")
defaults.synchronize()
print("Removed Array:\(array)")
Swift 2.x
NSUserDefaults.standardUserDefaults().removeObjectForKey("MyKey")
Swift 3.0
UserDefaults.standard.removeObject(forKey: "MyKey")
You just need to delete item from array and then again save the same array in UserDefaults, under the same key. It will overwrite original.
This is example from tableView:
itemArray.remove(at: indexPath.row)
UserDefaults.standard.set(itemArray, forKey: "itemArray")

How to store Array in NSUserDefault in Swift?

So I've been trying for a few hours for a way to store an array to NSUserDefault and print them to the cells but the data is not saving as an array, it basically only saves one value at a time.
var emailData = [String]()
var passwordData = [String]()
#IBAction func addPressed(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()
emailData.append(addEmail.text!)
passwordData.append(addPassword.text!)
var storedEmail = defaults.objectForKey("emailData") as? [String] ?? [String]()
var storedPasswords = defaults.objectForKey("passwordData") as? [String] ?? [String]()
// then update whats in the `NSUserDefault`
defaults.setObject(emailData, forKey: "emailData")
defaults.setObject(passwordData, forKey: "passwordData")
// call this after you update
defaults.synchronize() /*
NSUserDefaults.standardUserDefaults().setValue(addEmail.text, forKey: "email")
NSUserDefaults.standardUserDefaults().synchronize()
*/
}
So basically the data is not saving.
You can store Array too, by this way
let userDefault = NSUserDefaults.standardUserDefaults()
let arr = ["abc","xyz","pqr"]
userDefault.setObject(arr, forKey: "arr")
userDefault.synchronize()
let data = userDefault.objectForKey("arr") as! [String]
Save the Swift Array in Swift.
let kUserDefault = NSUserDefaults.standardUserDefaults()
kUserDefault.setObject(["KIRIT" , "MODI" , "FIRST" , "LAST"], forKey: "nameArray")
kUserDefault.synchronize()
Get Array
1. arrayForKey : You getting Swift Array
kUserDefault.arrayForKey("nameArray")!
2. objectForKey : You getting NSArray
kUserDefault.objectForKey("nameArray")!
3. valueForKey : You getting NSArray
kUserDefault.valueForKey("nameArray")
It is possible to store arrays in NSUserDefaults. But separating email and password in separate array is not suitable. You should store it as one object since they are related.
In your case an array of Dictionary objects is better, which is possible to store in NSUserDefaults as well, which you can retrieve as an array of Dictionary.
Here is the sample:
let userDefault = NSUserDefaults.standardUserDefaults()
var storedCredentials = userDefault.objectForKey("credentials") as? [[String:AnyObject]] ?? [[String:AnyObject]]()
let email =
[
"email" : addEmail.text!,
"password": addPassword.text!
]
storedCredentials.append(email)
userDefault.setObject(storedCredentials, forKey: "credentials")
userDefault.synchronize()
You can't save an array of [String] in NSUserDefault, if you look at the documentation :
For NSArray and NSDictionary objects, their contents must be property
list objects.
So what you can do is convert your [String] into NSData then save it into NSUserDefault.
// Store it as NSData
var emailData = [String]()
emailData.append("email1")
emailData.append("email2")
let emailIntoNSData = NSKeyedArchiver.archivedDataWithRootObject(emailData)
NSUserDefaults.standardUserDefaults().setObject(emailIntoNSData, forKey: "emailData")
// Retrieve it :
let emailFromNSData = NSUserDefaults.standardUserDefaults().objectForKey("emailData") as? NSData
if let emailFromNSData = emailFromNSData {
let emailArray = NSKeyedUnarchiver.unarchiveObjectWithData(emailFromNSData) as? [String]
if let emailArray = emailArray {
NSLog("Email Data : \(emailArray)") // ["email1","email2"]
// do something…
}
}

Delete key values for NSUserDefaults in Swift

How to delete data from NSUserDefaults? There is quite a few answers how to do it in Objective C, but how about Swift?
So I tried this:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.removeObjectForKey("myKey")
Didn't work. Maybe what I really want to delete is not NSUserDefaults?
This is how I save data:
class MySavedData: NSObject, NSCoding {
var image: String
init(name: String, image: String) {
self.image = image
}
required init(coder aDecoder: NSCoder) {
image = aDecoder.decodeObjectForKey("image") as! String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(image, forKey: "image")
}
}
class ViewController: <...> {
var myData = [MySavedData]() //Later myData gets modified and then function save() is called
func save() {
let savedData = NSKeyedArchiver.archivedDataWithRootObject(myData)
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(savedData, forKey: "myKey")
}
}
EDIT: Just to clear some things - data that is being saved is small (not even close to 100kb)
And maybe I am saving data not to NSUserDefaults (I am new to programming), so here is how I get it (load):
let defaults = NSUserDefaults.standardUserDefaults()
if let savedData = defaults.objectForKey("myData") as? NSData {
myData = NSKeyedUnarchiver.unarchiveObjectWithData(savedData) as! [UserLogin]
}
removeObjectForKey is the right way to go.
This will remove the value for the selected key. The following code sets a string value for a key in NSUserDefaults, prints it and then uses removeObjectForKey to remove and print the key value again. After removeObjectForKey the value is nil.
let prefs = NSUserDefaults.standardUserDefaults()
var keyValue = prefs.stringForKey("TESTKEY")
print("Key Value not set \(keyValue)")
let strHello = "HELLO WORLD"
prefs.setObject(strHello, forKey: "TESTKEY")
keyValue = prefs.stringForKey("TESTKEY")
print("Key Value \(keyValue)")
prefs.removeObjectForKey("TESTKEY")
keyValue = prefs.stringForKey("TESTKEY")
print("Key Value after remove \(keyValue)")
Returns:
Key Value not set nil
Key Value Optional("HELLO WORLD")
Key Value after remove nil
Update Swift 3:
let prefs = UserDefaults.standard
keyValue = prefs.string(forKey:"TESTKEY")
prefs.removeObject(forKey:"TESTKEY")
The code you have written will work fine, but NSUserDefaults synchronise at certain time interval.
As you want that should reflect in NSUserDefaults immediately ,so u need to write synchronise
let defaults = NSUserDefaults.standardUserDefaults()
defaults.removeObjectForKey("myKey")
defaults.synchronize()
Try This
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(NSBundle.mainBundle().bundleIdentifier!)
for Swift 3
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
But this will clear all values from NSUserDefaults.careful while using.
Removing UserDefaults for key in swift 3, based upon the top answer, just slightly different syntax:
UserDefaults.standard.removeObject(forKey: "doesContractExist")
Swift 4.x Remove all key in UserDefaults
let defaults = UserDefaults.standard
let dictionary = defaults.dictionaryRepresentation()
dictionary.keys.forEach
{ key in defaults.removeObject(forKey: key)
}
Use following for loop:
for key in NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys {
NSUserDefaults.standardUserDefaults().removeObjectForKey(key.description)
}
I would go for a solution which setting the value to nil for a key.
Swift 3
UserDefaults.standard.set(nil, forKey: "key")
Swift 2.x
NSUserDefaults.standardUserDefaults().setValue(nil, forKey: "key")
NOTE: that is a clear and straight statement, but bear in mind there is a limit to store information in NSUserDefaults, it is definitely not the right place to store large binary files (like e.g. images) – for that there is a Documents folder. however it is not defined how big the var image: String which you encode/decode.
To nuke all UserDefaults keys, you can use the following code in Swift 3.x:
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
In Swift 5.0, iOS 15 below single line of code is enough.
UserDefaults.standard.dictionaryRepresentation().keys.forEach(defaults.removeObject(forKey:))
Or try this
if let appDomain = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: appDomain)
}
func remove_pref(remove_key : String){
UserDefaults.standard.removeObject(forKey: remove_key)
UserDefaults.standard.synchronize()
}
Update code for Swift :
Used below line of code to Delete key values for NSUserDefaults in Swift
UserDefaults.standard.setValue(nil, forKey: "YouEnterKey")

Use NSUserDefaults with suiteName in Swift

I am having a problem with NSUserDefaults(suiteName: "group.app-ID").
I try to save an NSArray into the NSUserDefaults in the container Application in viewDidLoad().
var defaults: NSUserDefaults = NSUserDefaults(suiteName: "group.app-ID")
defaults.setObject(["One", "Two"], forKey: "bookmarks")
defaults.synchronize()
In my TodayExtension I try to get the array like this:
Globaly Defenition in Extension ViewController:
var defaults: NSUserDefaults = NSUserDefaults(suiteName: "group.app-ID")
var defaultsArray: NSArray!
In viewDidLoad()
defaultsArray = defaults.objectForKey("bookmarks") as NSArray
But defaultsArray always is nil.
The App Groups Entitlement has been added to all Targets.
This has nothing to do with your suite, but with the fact that you are trying to store a swift array as an NSObject. The following works in Playground and demonstrates how to do this:
let defaults = NSUserDefaults()
defaults.setObject(["One", "Two"] as NSArray, forKey: "array")
let myArray = defaults.objectForKey("array") as [String] // ["One", "Two"]
But you can also store a Swift array. You have to use a different accessor, though.
defaults.setObject(["One", "Two"], forKey: "array")
let myArray = defaults.arrayForKey("array") as [String] // ["One", "Two"]

Resources