I am trying to save an string array using NSUserDefaults with swift. I have searched around and believe that i have to use [NSString] not [String] however the app still crashes with error
fatal error: unexpectedly found nil while unwrapping an Optional value
I can not see what i am doing wrong as it is working perfectly fine saving ints and strings. Here is my code for my data singleton and NSUserDefaults.
struct DefaultsKeys
{
static let myString = "myString"
static let myInt = "myInt"
static let myArray = "myArray"
}
class DataContainerSingleton
{
static let sharedDataContainer = DataContainerSingleton()
var myString: String?
var myInt: Int?
var myArray:[NSString]?
/* I have also tried:
var myArray:[NSString] = [NSString]() */
var goToBackgroundObserver: AnyObject?
init()
{
let defaults = NSUserDefaults.standardUserDefaults()
myString = defaults.objectForKey(DefaultsKeys.myString) as! String?
myInt = defaults.objectForKey(DefaultsKeys.myInt) as! Int?
myArray = defaults.objectForKey(DefaultsKeys.myArray) as! [NSString]?
goToBackgroundObserver = NSNotificationCenter.defaultCenter().addObserverForName(
UIApplicationDidEnterBackgroundNotification,
object: nil,
queue: nil)
{
(note: NSNotification!) -> Void in
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject( self.myString, forKey: DefaultsKeys.my)
defaults.setObject( self.myInt, forKey: DefaultsKeys.myInt)
defaults.setObject( self.myArray, forKey: DefaultsKeys.myArray)
defaults.synchronize()
}
}
}
<!-- language: swift -->
//declare and initiate the array
var sample_array : NSMutableArray! = []
//use mutable array to add data
//variable to store value in array
var say: String! = "Hello"
//add values in array
sample_array.addObject("hello")
//or
//sample_array.addObject(say)
/*
//you can also save values in array like this
var sample_array: Array<String> = []
var say: String! = "Hello"
sample_array = ["Qwerty"]
sample_array.insert(say, atIndex: 1)
println(sample_array)
*/
//archive and saving data
let data = NSKeyedArchiver.archivedDataWithRootObject(sample_array)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "array_key")
NSUserDefaults.standardUserDefaults().synchronize()
//unarchive and getting data
if let data = NSUserDefaults.standardUserDefaults().objectForKey("array_key") as? NSData {
stopover_array = NSKeyedUnarchiver.unarchiveObjectWithData(data) as NSMutableArray
}
Problem is the code:
myString = defaults.objectForKey(DefaultsKeys.myInt) as! String?
myInt = defaults.objectForKey(DefaultsKeys.myInt) as! Int?
myArray = defaults.objectForKey(DefaultsKeys.myArray) as! [NSString]?
as! means unwraping an optional value, that's why your app crashed with error
fatal error: unexpectedly found nil while unwrapping an Optional value
if defaults.objectForKey(DefaultsKeys.myInt) is nil, then unwrapping nil is not allowed. You should use
myString = defaults.objectForKey(DefaultsKeys.myInt) as? String
instead.
Related
I stored an Int in UserDefaults. The Int will serve as the index of audioOptionsList, an array of objects, each having a SystemSoundID property.
This crashes with error: Could not cast value of type 'NSTaggedPointerString' (0x7fff87b33c28) to 'NSNumber' (0x7fff87bf4e00).
var soundToPlay = SystemSoundID(1322)
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.value(forKey: "timerSoundSelection") != nil {
let storedIndex = UserDefaults.standard.value(forKey: "timerSoundSelection")!
print("stored index is: \(storedIndex)") //prints a non-optional int as expected.
soundToPlay = audioOptionsList[storedIndex as! Int].sound //crashes with error
} else {
soundToPlay = SystemSoundID(1322)
}
Your key is stored as a String not an Int , use string(forKey: then cast it
if let stored = UserDefaults.standard.string(forKey: "timerSoundSelection")
, let value = Int(stored) { }
My app is crashing when I start it on a device.
At start, all my arrays are empty.
Error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value swift
How can I fix that?
var CName: [String] = [""]
var BarCode: [String] = [""]
var CardNBR: [String] = [""]
var CardColorLogo = [UIColor]()
var UploadDateArray = [NSDate]()
var Comment: [String] = [""]
Save and Load Function
func saveColorLogo() {
UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: CardColorLogo), forKey: "ColorsKey")
}
func loadColorLogo() {
let decodedColorsData = UserDefaults.standard.object(forKey: "ColorsKey") as? NSData
let colorsArray = (NSKeyedUnarchiver.unarchiveObject(with: decodedColorsData! as Data) as! NSArray)
CardColorLogo = colorsArray as! [UIColor]
}
First of all please conform to the naming convention that variable names start with a lowercase letter for example
var cardColorLogo = [UIColor]()
Second of all, don't use NSData and NSArray in Swift. There are native types.
Any carelessly written exclamation mark can crash the app.
The error occurs because object(forKey returns nil if the key does not exist. By the way, there is a data(forKey method with the same behavior.
Optional bind the result and return an empty array on failure
func loadColorLogo() {
if let decodedColorsData = UserDefaults.standard.data(forKey: "ColorsKey"),
let colorsArray = NSKeyedUnarchiver.unarchiveObject(with: decodedColorsData) as? [UIColor] {
cardColorLogo = colorsArray
} else {
cardColorLogo = []
}
}
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…
}
}
I have the following class
class BannerResponse : NSObject{
let URL = "Url";
let CONTACT_NO = "ContactNo";
let IMAGE = "Image";
let BIG_IMAGE = "BigImage";
let ID = "Id";
let TITLE = "Title";
let NO_VIEW = "NoView";
let START_DATE = "StartDate";
let END_DATE = "EndDate";
var url:String;
var contactNo:String;
var image:String;
var bigImage:String;
var title:String;
var id:Int;
var noView:Int;
var startDate:String;
var endDate:String;
init(data : NSDictionary){
url = data[URL] as! String;
contactNo = data[CONTACT_NO] as! String;
image = data[IMAGE] as! String;
bigImage = data[BIG_IMAGE] as! String;
title = data[TITLE] as! String;
id = data[ID] as! Int;
noView = data[NO_VIEW] as! Int;
startDate = data[START_DATE] as! String;
endDate = data[END_DATE] as! String;
}
}
when I run the code, I got the following error
Could not cast value of type 'NSNull' (0x10a85f378) to 'NSString' (0x109eccb20).
EDIT
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary{
onSuccess(BannerResponse(data: json))
}
} catch {
onFail()
}
One of your data[SOME_KEY] is of type NSNull instead of String and because you're forcing the cast to String by using ! the app crashes.
You can do one of two things:
Change your variables on the BannerResponse class to be optional. And use ? instead of ! when setting the values in your init method. Like this:
`
var title: String?
init(data: NSDictionary)
{
self.title = data[TITLE] as? String
}
or
Use ? instead of ! when setting the values in your init method but set a default value whenever dict[SOME_KEY] is nil or is not the expected type. This would look something like this:
`
if let title = data[TITLE] as? String
{
self.title = title
}
else
{
self.title = "default title"
}
// Shorthand would be:
// self.title = data[TITLE] as? String ?? "default title"
And I guess a third thing is ensure that the server never sends down null values. But this is impractical because there's no such thing as never. You should write your client-side code to assume every value in the JSON can be null or an unexpected type.
You are getting null values for some of your keys. They get mapped to NSNull by NSJSONSerialization.
You need to do several things
Change all your variables (url, contactNo, etc) to optionals:
var url:String?
var contactNo:String?
Change all of your assignments to use ? instead of !:
url = noNulls[URL] as? String
contactNo = noNulls[CONTACT_NO] as? String
And finally, make your code handle nil values for all of your variables. (But do not use !. That path leads to crashes.)
There is a code containing description of Dictionary struct and receiving corresponding entries from Core Data
What string(s) should I insert before last bracket to cast NSArray to array of dictionaries?
struct Dictionary {
var name: String
var enableDirect: Bool
var enableReverse: Bool
init(name: String, enableDirect: Bool, enableReverse: Bool) {
self.name = name
self.enableDirect = enableDirect
self.enableReverse = enableReverse
}
}
func loadDictionariesFromStore() -> [Dictionary] {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Dictionaries")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)!
}
If you are sure that the NSArray is of type [Dictionary] you can make a forced downcast of results and return it:
return results as! [Dictionary]
// or directly return it
return context.executeFetchRequest(request, error: nil)! as! [Dictionary]