Swift Optionals - Unexpectedly found nil when unwrapping an optional value - ios

I'm new to Swift and have been trying to wrap (ha) my head around optional values. As far as I can see - although I'm probably wrong - variables can be optional and therefore contain a nil value and these have to be accounted for in code.
Whenever I hit the 'save' button in my application I get the error: 'fatal error: unexpectedly found nil while unwrapping an Optional value'.
#IBAction func saveTapped(sender: AnyObject) {
//code to save fillup to Parse backend
// if variable is not nil
if let username = PFUser.currentUser()?.username {
// set username equal to current user
self.object.username = username
}else{
println("PFUser.currentUser()?.username contained a nil value.")
}
// if variable is not nil
if let amount = self.amountTextField.text {
//set amount equal to value in amountTextField
self.object.amount = self.amountTextField.text
}else{
println("self.amountTextField.text contained a nil value.")
}
// if variable is not nil
if let cost = self.costTextField.text {
// set cost equal to the value in costTextField
self.object.cost = self.costTextField.text
}else{
println("self.costTextField.text contained a nil value.")
}
// set date equal to the current date
self.object.date = self.date
//save the object
self.object.saveEventually { (success, error) -> Void in
if error == nil {
println("Object saved!")
}else{
println(error?.userInfo)
}
}
// unwind back to root view controller
self.navigationController?.popToRootViewControllerAnimated(true)
}
Not sure if the error is because of something in this block of code or somewhere else - can provide the main class code if needed.
Any help anyone can provided would be really appreciated as this has been bugging me for a while now.

From your code and the comments it sounds like your issue definitely lies with self.object
Your code never uses an if let statement to check to ensure self.object is not nil
Using println(username) works because your username is not nil. But when you try to call self.object.username, it's the self.object that is causing the crash.
You may have a property in your implementation like var object:CustomPFObject! which means, the first time you access this variable it's expected to not be nil. You'll probably want to check the code where you are setting self.object for the first time, and to make sure that it's being set before you've tried to access it.
If you're not able to manage when self.object is set, and when it's accessed, then change your declaration to var object:CustomPFObject? Now it's an optional, and as you write your code you'll be forced to make decisions as you go along.
For example:
var object:CustomPFObject?
let text = self.object.username //won't compile
let text = self.object!.username //mighty crash
let text = self.object?.username //you're safe, 'text' just ends up nil
I hope this helps you solve your issue.

Related

leaving textfields blank - crash - swift 4

I am trying to create a course avg calculator with textfields. However if I only want to enter in a few marks (i.e. not filling out all the textfields) I get a crash.
I get this error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
In my code, I tried to avoid this nil value, but I get the error on that first line if I leave the first textfield blank. I do further calculations with these textfields, so I'm not sure if I will get similar errors once I fix these lines.
if b?.text != nil {
b?.text = String(Double(b!.text!)!/100)
}
if d?.text != nil {
d?.text = String(Double(d!.text!)!/100)
}
if f?.text != nil {
f?.text = String(Double(f!.text!)!/100)
}
if h?.text != nil {
h?.text = String(Double(h!.text!)!/100)
}
Force unwrap the double conversion
Double(b!.text!)!
is the reason as empty string can't be converted to double so it returns nil and as you use ! , hence the crash , you need
if let tex = b , content = tex.text , value = Double(content) {
print(value)
}
Also don't make the b var an optional make it !
var b:UITextField! // and make sure you init it
Edit: Don't create other vars to hold instance ones use them directly
#IBOutlet weak var weight1: UITextField!
if let content = weight1.text , value = Double(content) {
print(value)
weight1.text = "\(value/100)"
}
Double(b!.text!)!
This is the reason, your input text (b!.text!) is not convertible to double hence ended up with nil.
for ex: you might be giving input "12Th45", this is not convertible to double.
Always use optional binding wherever you are not sure that value is there or not.
Thanks.

calling function in viewDidLoad crash

Calling parseString crashes my application. myOptionalString is getting set from didSelectRowAtIndexPath in a tableview. The information is definitely get passed to this view controller.
The method also works if called from a button press. But in any life cycle method I try I get unexpectedly found nil while unwrapping an Optional.
override func viewDidLoad() {
super.viewDidLoad()
if let myUnwrappedString = myOptionalString{
print(myUnwrappedString) //<-- prints out string
confidence.text = parseString(myUnwrappedString) //<-- unexpectedly found nil while unwrapping an Optional crash
}
}
//this method works if called on a button press but crashes in viewDidLoad
func parseString(myString: String)->String{
return myString.substringFromIndex(myString.rangeOfString(" ")!.endIndex)
}
Your error come from your function parseString, let's see why. If you see carefully your function you're make a force-unwrapping of an optional value in your case the myString.rangeOfString(" ")!. This is not recommended at all.
If we pass the string "Confidence: 63%" to the function the function works properly and returns "63%", but it works because it have the " " string inside, if for some reason you pass some string that don't have it it will crash (e.g "Confidence:63%").
So one of the correct ways of implement this function can be using the guard statement using optional binding avoiding any force-unwrapping:
func parseString(myString: String) -> String? {
guard let range = myString.rangeOfString(" ") else { return nil }
return myString.substringFromIndex(range.endIndex)
}
In the above function you return nil in case of not exist the " " in the string and avoid the runtime error.
I hope this help you.
I'm guessing your problem lies in this line:
myString.rangeOfString(" ")!
rangeOfString returns an optional Range<Index>? value, meaning that if the character you are looking for is not present in the string, you will get the value nil in return. In other words, if there is no space in your string, you get a nil value for your range.
That value you then force unwrap with !, and then you use it to call substringFromIndex. This means that if the range was actually nil, you use that nil value to try to create a substring from its endIndex... which you cannot...so it crashes.
One way of solving this could be to use a guardto make sure that you actually found a range in your string. If you don't, then you just return an empty String...or do something else that suits your use case better.
Here is an example:
func parseString(myString: String)->String{
guard let range = myString.rangeOfString(" ") else {
return ""
}
return myString.substringFromIndex(range.endIndex)
}
Hope that helps you.

NSUserDefaults optionals in Swift

I'm trying to deal with compiler in case of optional values. Task is very simple, my func fetches user defaults to appear them in tableview. If user launches app for the first time, it setts default values. Setting default values works fine (checked with print log), but fetching causes:
fatal error: unexpectedly found nil while unwrapping an Optional value
I'm already worked with optionals for a long time, but, perhaps I'm still confused about them, 'cos I see that everything seems to be correct and even compiler says, that everything is ok.
func getFiltersSetts() -> [String] {
let userDefs = NSUserDefaults.standardUserDefaults()
var defsArray = [String]()
if (userDefs.objectForKey("gender") != nil) {
defsArray.append((userDefs.objectForKey("gender")?.stringValue)!)
defsArray.append((userDefs.objectForKey("age")?.stringValue)!)
defsArray.append((userDefs.objectForKey("online")?.stringValue)!)
}
else {
userDefs.setObject("Male", forKey: "gender")
userDefs.setObject("21-30", forKey: "age")
userDefs.setObject("Online", forKey: "online")
}
return defsArray
}
You are force unwrapping your optionals, and you should get them as strings before appending them to your array.
A cleaner way to set the defaults would be to coalesce the unwrapping of your optionals, Try the following approach:
func getFiltersSetts() -> [String] {
let userDefs = NSUserDefaults.standardUserDefaults()
var defsArray = [String]()
defsArray.append(userDefs.stringForKey("gender") ?? "Male")
defsArray.append(userDefs.stringForKey("age") ?? "21-30")
defsArray.append(userDefs.stringForKey("online") ?? "Online")
return defsArray
}
The code above uses the coalesce (??) operator. If your optional, say userDefs.stringfForKey("gender"), returns nil, the coalesce operator will use the default value "Male".
Then at a later time you can save your user defaults (or create them) if they haven't been set before.
Also, is worth noticing that you should be unwrapping your optionals using the if let notation. Instead of comparing if its != nil, as this will prevent you from force unwrapping them inside the code block.
I hope this helps!
Apple highly recommends to set default values via registerDefaults of NSUserDefaults.
As soon as possible (at least before the first use) set the default values for example in applicationDidFinishLaunching:
let userDefs = NSUserDefaults.standardUserDefaults()
let defaultValues = ["gender" : "Male", "age" : "21-30", "online" : "Online"]
userDefs.registerDefaults(defaultValues)
The default values are considered until a new value is set.
The benefit is you have never to deal with optionals nor with type casting.
func getFiltersSetts() -> [String] {
let userDefs = NSUserDefaults.standardUserDefaults()
return [userDefs.stringForKey("gender")!,
userDefs.stringForKey("age")!,
userDefs.stringForKey("online")!]
}
The forced unwrapping is 100% safe because none of the keys can ever be nil.
Please read Registering Your App’s Default Preferences in Preferences and Settings Programming Guide
You can create a default key "firstBootCompleted". Then use:
let defaults = NSUserDefaults.standardUserDefaults()
if (defaults.boolForKey("firstBootCompleted") == false) {
defaults.setObject(true, forKey: "firstBootCompleted")
// Initialize everything for your first boot below
} else {
// Initialize everything for not your first boot below
}
The reason this works is that boolForKey returns false when the object for key is nil
You are storing all the value as String and then at the time of fetching
you are typecast the value again in String
userDefs.objectForKey("gender")?.stringValue
A String can not be convert as String again.
try to access as
userDefs.stringForKey("gender")

CoreData Swift: Fatal error: unexpectedly found nil while unwrapping an Optional value

override func viewWillDisappear(animated: Bool) {
// need to add a device?
if profile == nil {
if let name = nameTextField.text, species = speciesTextField.text, dob: NSDate = datePicker.date, entity = NSEntityDescription.entityForName("Profile", inManagedObjectContext: managedObjectContext) where !name.isEmpty && !species.isEmpty {
profile = Profile(entity: entity, insertIntoManagedObjectContext: managedObjectContext)
profile?.name = name
profile?.species = species
profile?.dob = dob
}
}
}
Whenever I run my app, this part of code produces 'Fatal error: unexpectedly found nil while unwrapping an Optional value'. I am certain that name,species and dob do contain data as it shows in the console. Do you have any idea what variable could contain nil? I am using core data and am unfamiliar with it.
Screen:
Entities:
In your screenshot, it says:
managedObjectContext = (NSManagedObjectContext!)nil
So most likely this is the cause of your crash.
It very well could be one of your text fields producing the nil value. Put in a break point and check them (and the datePicker) for nil. Are you using IBOutlets, or were these created programmatically?

How to check for an undefined or null variable in Swift?

Here's my code:
var goBack: String!
if (goBack == "yes")
{
firstName.text = passFirstName1
lastName.text = passLastName1
}
All I want to do is execute the if-statement if 'goBack' is undefined. How can I do that? (I don't know what to put in the blank)
The overall program is more complicated which is why I need the variable to be undefined at first. In short, I'm declaring 'goBack', asking the user to type in their first and last name, then continuing to the next view controller. That view controller has a back button that brings us back to the first view controller (where I declared 'goBack'). When the back button is pressed, a 'goBack' string is also passed of "yes". I also passed the first and last name to the next view controller but now I want to pass it back. I'm able to pass it back, its just a matter of making the text appear.
EDIT: firstName and lastName are labels while passFirstName1 and passLastName1 are variables from the second view controller.
"All I want to do is execute the if-statement if 'goBack' is undefined. How can I do that?"
To check whether a variable equals nil you can use a pretty cool feature of Swift called an if-let statement:
if let goBackConst = goBack {
firstName.text = passFirstName1
lastName.text = passLastName1
}
It's essentially the logical equivalent of "Can we store goBack as a non-optional constant, i.e. can we "let" a constant = goBack? If so, perform the following action."
It's really interesting, you can define a variable as optional, which means it may or may not be defined, consider the following scenerio:
you want to find out if the app has been installed before...
let defaults = NSUserDefaults()
let testInstalled : String? = defaults.stringForKey("hasApplicationLaunchedBefore")
if defined(testInstalled) {
NSLog("app installed already")
NSLog("testAlreadyInstalled: \(testInstalled)")
defaults.removeObjectForKey("hasApplicationLaunchedBefore")
} else {
NSLog("no app")
defaults.setValue("true", forKey: "hasApplicationLaunchedBefore")
}
Then all you need to do is write a function to test for nil...
func defined(str : String?) -> Bool {
return str != nil
}
And you've got it. A simpler example might be the following:
if let test : String? = defaults.stringForKey("key") != nil {
// test is defined
} else {
// test is undefined
}
The exclamation mark at the end is to for unwrapping the optional, not to define the variable as optional or not
"All I want to do is execute the if-statement if 'goBack' is undefined"
The guard statement (new in Swift 2) allows exactly this. If goBack is nil then the else block runs and exits the method. If goBack is not nil then localGoBack is available to use following the guard statement.
var goBack:String?
func methodUsingGuard() {
guard let localGoBack = goBack else {
print("goBack is nil")
return
}
print("goBack has a value of \(localGoBack)")
}
methodUsingGuard()
From The Swift Programming Language (Swift 3.1):
Constants and variables created with optional binding in an if
statement are available only within the body of the if statement. In
contrast, the constants and variables created with a guard statement
are available in the lines of code that follow the guard statement, as
described in Early Exit.

Resources