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.
Related
Im creating simple app where i can manipulate my display which holds numbers(double). App works perfectly on simulator but not on a real device.
I found the reason for that error. Its my getter. Its returning nil(pretty sure about that) Anyone got idea how to fix my getter?
var displayValue: Double {
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set {
display.text = String(format: "%g", newValue)
}
}
You must be trying to get value of displayValue before assigning it any value, and your are force unwrapping it so, obviously it will crash.
In your current code just try setting value to your display label (like display.text = "5") before accessing it, then it would work.
And its better to use if let check in case of force unwrapping, if you know your variable value can be nil.
This solves everything. Thanks https://stackoverflow.com/users/2227743/eric-d
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html#//apple_ref/doc/uid/TP40014097-CH21-ID245
I am trying to get do a GET request, and save the following results from into NSMutuableArray. Then I am trying to load the following data I got into a tableview, but I am getting an "unexpectedly found nil while unwrapping optional value" whenever I try to configure the number of rows.
var dataArray:NSMutableArray?
Alamofire.request(.GET, "SOMERANDOMWEBSITE") .responseJSON { response in
// using if-let syntax to save json into our NSMutuableArray
if let JSON = response.result.value {
self.dataArray = JSON as? NSMutableArray
}
}
When i try to configure the number of rows:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.dataArray.count
}
It gives me an error: "unexpectedly found nil while unwrapping optional value". But what's strange is that when I create a random button to see if the .count is indeed nil:
#IBAction func function(sender: AnyObject) {
print(self.dataArray?.count)
}
it returns me with Optional(2) instead of nil. Any ideas?
You made your array an Optional. We can see that here:
print(self.dataArray?.count)
So until it's populated in Alamofire's closure (the network request happens in the background), it is nil.
You quote:
return self.dataArray.count
but actually you probably have done
return self.dataArray!.count
This is why it crashes.
So you have to declare another option for count for when it's nil. A solution could be to safely unwrap the array then return the count or return a default value:
if let array = self.dataArray {
return array.count
}
return 0
This same logic can be expressed in a single line, as #brian-nickel notes in the comments:
return self.dataArray?.count ?? 0
Also, as stated by #vadian in the comments, absolutely, an Optional array makes little sense here, it would be better to just have a non-optional empty array from the beginning.
It's not strange, it's asynchronous.
Initially you declare dataArray as optional (aka nil) but don't initialize it.
The first attempt to update the table view fails (crashes) because calling count on nil is a bad idea.
Meanwhile the asynchronous request method returns the data and assigns it to dataArray which has now an (optional) value.
That's why you get a result in function.
Solution is to declare and initialize the array as non-optional Swift type.
var dataArray = [AnyObject]()
Probably there is a more specific type than AnyObject
and assign the returned data accordingly casting the result to the "better" type.
Basically declaring table view data source arrays as optional is absurd since your table view is always non-optional.
It may be the basic swift quetion, But i am new to swift or iOS development. I am getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
For the function bellow
func Call() -> NSData?
{
let nilObj: NSData? = nil
if(false){
// Doing something
}
else
{
return nilObj!
}
}
I just want to return the nil NSData in else condition but i am getting error. I am sure i am missing something obvious, Can anybody help.
You declared nilObj as optional and initialised it with nil. Then in your else clause you are trying to unwrap that. For fixing the issue you just need to remove that !
Change your code to:
func Call() -> NSData?
{
let nilObj: NSData? = nil
if(false)
{
// Doing something
}
else
{
return nilObj
}
}
Well, error says it all! You are trying to forceful unwrap an optional. You should use if let syntax while unwrapping an optional.
Optionals in swift can be confusing at first but it helps to keep in mind that they are just an enum like:
enum Optional<T> {
case None
case Some(T) // swift enums can have data associated to them
}
If you are sure your optional has non-nil value, that is, it is a .Some, you can access this underlying value through the exclamation mark ! operator.
In short, force-unwrapping optional! is saying "Ok, I'm sure this optional contains non-nil value. Give it to me."
This is what's called force-unwrapping. You're telling the system to access the value corresponding to .Some(T) although you're not checking whether your optional is a .Some or a .None. If you force-unwrap with ! and your optional turns out to be a .None, you will get the runtime error you got unexpectedly found nil while unwrapping an Optional value.
As a rule of thumb you should always check your optionals before unwrapping them. In few occasions you should assume an optional is non-nil and force-unwrap it. Even an IBOutlet can turn out to be nil if you try to access it in prepareForSegue for example. XCode automatically makes outlets implicitly unwrapped because for most of your view controller's lifecycle they won't be nil. But you still have to take care for yourself of these less common edge cases in which they are nil.
You can check if an optional has non-nil value the standard way with
if optional != nil {
// force-unwrapping after nil check is fine
optional!.someMethod()
} else {
// 'optional' is nil
}
A more idiomatic way to do it with swift is through optional binding.
// binds the constant 'value' to your optional if it is non-nil
if let value = optional {
value.someMethod()
} else {
// optional is nil
}
A third way to check is with guard statements. The semantics of guard statements is a bit different from the previous ones though. You can also mix guard statements and optional binding.
guard optional != nil else {
// optional is nil.
// by the end of this branch you must exit the block that
// encloses the guard statement, such as with a return or break
return
}
// if control reaches here you're guaranteed optional is non-nil
Guard statements are a neat feature in swift because you can focus on the conditions you want, as opposed to what you don't want. It also keeps the code that handles a violated requirement next to the respective requirement. Compared to doing the same thing with an if statement, guards improve readability by making your intents explicit.
To know more have a look at the basics section of the swift documentation.
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.
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.