unexpectedly found nil when use userDefaults - ios

I add #IBAction for button:
#IBAction func addThemeAction(sender: AnyObject) {
var userDefaults:NSUserDefaults=NSUserDefaults.standardUserDefaults()
var itemList:NSMutableArray!=userDefaults.objectForKey("itemList") as NSMutableArray}
When I press button I get fatal error: unexpectedly found nil while unwrapping an Optional value.

There's no object for the key itemList in your NSUserDefaults. Instead of force unwrapping it with !, check if optional is nil and conditionally unwrap it:
let userDefaults = NSUserDefaults.standardUserDefaults()
var itemList = userDefaults.objectForKey("itemList") as? [AnyObject]
if let itemList = itemList {
// itemList is not nil, use it here
} else {
// itemList has never been set, perhaps use some default
}
Also, userDefaults doesn't need to be a var.
You can change [AnyObject] to something else if you know the type (like [String], for example).

One: You can never guarantee that some key is present in your user defaults, so this is a crash waiting to happen. Two: I don't think dictionaries that you read from user defaults are mutable.

Related

Swift 3: Cant unwrap optional from Dictionary?

Ok I don't know what is going on here. I have a dictionary of Strings below:
var animals = ["max": "z", "Royal": nil] //store key pairs
and I am unable to print the value of the value in the key value pair without it printing "Optional" along with it.
I have tried using ! !! and casting as a String as well as the following:
var animalsToReturn = [String]()
if animals[selected]! != nil
{
if let pairName = animals[selected]
{
print("\(pairName)")
print("has pair",selected, animals[selected]!)
//trying to append to another array here
animalsToReturn.append("\(animals[selected]!)")
animalsToReturn.append(selected)
}
}
else {
print("no pair")
}
I check to make sure the value isn't nil, so it won't crash if I unwrap. But this is what is printed and the word Optional is appended to my other array:
You have included nil as a value, so the type of your dictionary's value is not String but Optional<String>. But fetching a value by key from a dictionary is itself an Optional. Therefore:
If your entry is present and is ultimately a String, it is an Optional<Optional<String>> and you have to unwrap it twice.
If your entry is present and is ultimately nil, it is an Optional wrapping nil.
If your entry is not present, it is nil.
You can readily test this as follows:
func test(_ selected:String) {
var animals = ["max": "z", "Royal": nil]
if let entry = animals[selected] { // attempt to find
if let entry = entry { // attempt to double-unwrap
print("found", entry)
} else {
print("found nil")
}
} else {
print("not found")
}
}
test("max") // found z
test("Royal") // found nil
test("glop") // not found
Contemplation of that example will answer your original question, namely "I don't know what is going on here".
animals[selected] is a Optional<Optional<String>> because you're storing nil. You can:
Double unwrap your value either by using if let or ! twice.
Change the type of your dictionary to [String: String] (instead of [String: String?]), and thus avoiding nil values.
Flatten the dictionary, removing nil values, and then accessing it as a [String: String]
You can flatten the dictionary using the code in this question.
Please enclose that in bracket and use double unwrapping. try this : -
animalsToReturn.append("\((animals[selected])!!)")
func addAnimal(_ animal: String) {
guard let animal = animals[animal] else {
print("No pair")
return
}
animalsToReturn.append(animal ?? "")
}

Guarding against a switch button having a nil optional value

I have a piece of code that runs if a switch has been set in settings as follows:
UserDefaults.standard.bool(forKey: "signatureSwitchState")
let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as! Bool
if buttonState == true {
sign()
}
My problem is if the switch has never been activated the program fails as the compiler states that, "fatal error: unexpectedly found nil while unwrapping an Optional value"
My question is then how best to guard against a nil value when using a bool such as the switch in the above statement.
I've tried if let statements and guard statements but the compiler complains that these cannot be used with a bool.
You should use:
let buttonState = UserDefaults.standard.bool(forKey: "signatureSwitchState")
If the value is not explicitly set, it will return false.
If you're trying to get a bool from the UserDefaults you can use
let buttonState = UserDefaults.standard.bool(forKey: "signatureSwitchState"),
this function returns a Bool so you know that the value can only be true or false and if it doesn't find a value for the key then it will return false. The function you are using
UserDefaults.standard.object(forKey: "signatureSwitchState")
returns a AnyObject? so it can be nil.
Little known, but highly recommended by Apple:
Register defaults values which are considered until the user changes the value the first time.
In applicationDidFinishLaunching – at least before accessing the value the first time – register the key / value pair(s).
let userDefaults = UserDefaults.standard
let defaultValues : [String : Any] = ["signatureSwitchState" : false]
userDefaults.register(defaults: defaultValues)
Now the value is never nil (I know the Bool example is pretty weak)
let buttonState = UserDefaults.standard.bool(forKey: "signatureSwitchState")
The objects take much more advantage of that way than the "primitive" types which are never nil anyway.
I have a tip that might come in useful in the future, though it's not as good aspicciano's answer which is definitely the correct way to go.
UserDefaults.standard.object(forKey: "signatureSwitchState") returns an AnyObject.
If you try to force cast to Bool (as! Bool), this will crash if the returned value isn't a Bool, or if it is nil. Instead, if you conditionally cast (as? Bool), you'll receive a Bool?. This will cast the value to a Bool if it exists, otherwise it'll give you nil (without crashing.
From there, you can convert this Bool? to Bool by using the nil coalescing operator (??). It will return you the Bool value if there is one, otherwise it'll return the default value you give it. In this case, false.
Also, because buttonState is already a Bool, there's no reason to compare it to true in your if statement. Just use it directly:
let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as? Bool ?? false
if buttonState {
sign()
}
There are a couple ways you can do this. Since this is a bool, it's probably easiest just to use nil-coalescing ??:
let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as? Bool ?? false
Or, you could use guard to do it, which is probably more robust:
guard let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as? Bool else { return }
if buttonState == true {
sign()
}
Note that in both cases, you have to change the forced unwrap (!) to an optional unwrap (?).

Unexpectedly finding nil, even after unwrapping

In my UITableViewController, I have an optional property which is a CNContact. If not nil, I want to populate some text fields with the contact's data.
Here is the property:
var contact: CNContact? = nil {
didSet {
if contact != nil {
prefillFromContact(contact!)
}
}
}
And here is the code setting a text field
func prefillFromContact(con: CNContact) {
print(con.givenName)
firstNameTextField.text = con.givenName
}
The print statement works, and returns the contact's name, but the following line throws an error.
Kate
fatal error: unexpectedly found nil while unwrapping an Optional value
I can't work out why it works on the print statement, but not the following line.
I assume firstNameTextField is declared as an implicit optional, like this:
var firstNameTextField: UITextField!
And you are causing this code to be called before viewDidLoad.
If so, firstNameTextField is nil. It is only possible to set the values of UIViews loaded from XIB/Storyboards once they are loaded. Before that, their outlets are nil.
As an aside (even though this isn't what is causing your problem):
if contact != nil {
prefillFromContact(contact!)
}
is more Swifty like this:
if let contact = contact {
// this is only true if contact != nil, and you have a contact variable
// that is of type CNContact, not CNContact?
prefillFromContact(contact)
}

unexpectedly found nil while unwrapping an Optional value?

I'm facing with an error: "unexpectedly found nil while unwrapping an Optional value"
when I insert new data in coreData and reload my tableview, I recall this function
var unique = [String]()
var loadMovie = [String:[Movie]]()
func insertMovie(movie : Movie) {
let genre = movie.genre!
if unique.contains(genre) {
loadMovie[genre]!.append(movie)
} else {
unique.append(genre)
loadMovie[genre] = [movie]
}
}
and fetch data:
func fetchAndSetResults() {
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Movie")
do {
let movies = try context.executeFetchRequest(fetchRequest) as! [Movie]
loadMovie.removeAll()
for movie in movies {
insertMovie(movie)
}
} catch let err as NSError {
print(err.debugDescription)
}
}
and the app crushes for the error mentioned above on line: " loadMovie[genre]!.append(movie)" but if I reload app, my data are stored and visible in tableview. What's the problem?
you unwrapped optional variable means you just resolving the compile time error only. In swift you unwrapping the variable means it is represents that variable won't get the nil.You are just telling to the compiler .But now you are getting the nil (Run time Error) you need to handle this by using Optional Binding.
if let movies = try context.executeFetchRequest(fetchRequest)
{
loadMovie.removeAll()
}
Your variable loadMovie is a Dictionary with Strings as the keys and Arrays of Movies as what is stored for each key. If you are getting the error "unexpectedly found nil while unwrapping an Optional value" for line " loadMovie[genre]!.append(movie)" it means without a doubt the String called genre is sometimes not a stored as a key in your loadMovie Dictionary.
Use the code below to first make sure you can get the Array stored for that key (stored in the genre string), and if you can't then print out the String so you can debug, to find out what key is missing.
var unique = [String]()
var loadMovie = [String:[Movie]]()
func insertMovie(movie : Movie) {
let genre = movie.genre!
if unique.contains(genre) {
if let genreArray = loadMovie[genre]{
genreArray.append(movie)
} else {
NSLog("The missing genre: \(genre)")
}
} else {
unique.append(genre)
loadMovie[genre] = [movie]
}
}
Anytime you want a value that could be nil (not there) you can use the if/let pattern above. So for your second question in the comments you could replace return loadMovie[genre].count with:
if let genreArray = loadMovie[genre]{
return genreArray.count
} else {
return 0 // zero because there are no items
}
There are other ways too. You should checkout a good basic swift tutorial like: http://www.tutorialspoint.com/swift/
If you look at the section on optionals this should all be more clear. Here at stack overflow you are generally expected to first have tried to find out answers for yourself, and understand the basic theory. Unfortunately, that is why you are getting so many down votes. I hope this has helped.
If this has helped you please accept this answer by clicking on the checkmark next to it.

Can't unwrap 'Optional.None'

When confronting the error fatal error:
Can't unwrap Optional.None
It is not that easy to trace this. What causes this error?
Code:
import UIKit
class WelcomeViewController: UIViewController {
let cornerRad:CGFloat = 10.0
#IBOutlet var label:UILabel
#IBOutlet var lvl1:UIButton
#IBOutlet var lvl2:UIButton
#IBOutlet var lvl3:UIButton
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
override func viewDidLoad() {
super.viewDidLoad()
lvl1.layer.cornerRadius = cornerRad
lvl2.layer.cornerRadius = cornerRad
lvl3.layer.cornerRadius = cornerRad
}
}
You get this error, because you try to access a optional variable, which has no value.
Example:
// This String is an optional, which is created as nil.
var optional: String?
var myString = optional! // Error. Optional.None
optional = "Value"
if optional {
var myString = optional! // Safe to unwrap.
}
You can read more about optionals in the official Swift language guide.
When you see this error this is due to an object such as an unlinked IBOutlet being accessed. The reason it says unwrap is because when accessing an optional object most objects are wrapped in such a way to allow the value of nil and when accessing an optional object you are "unwrapping" the object to access its value an this error denotes there was no value assigned to the variable.
For example in this code
var str:String? = nil
var empty = str!.isEmpty
The str variable is declared and the ? denotes that it can be null hence making it an OPTIONAL variable and as you can see it is set to nil. Then it creates a inferred boolean variable empty and sets it to str!.isEmpty which the ! denotes unwrap and since the value is nil you will see the
Can't unwrap Optional.None error
Fisrt check your storyboard UILabel connection. wheather your UILabel Object or connected or Not. If not it showing Fatal Error.

Resources