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.
Related
This is my relevant struct:
struct MealPlan {
var docID:String?
var title:String?
var ingredientsProduce:[String]?
var ingredientsProtein:[String]?
var ingredientsSpices:[String]?
var ingredientsOther:[String]?
var isStarred:Bool?
}
And this is my model:
class MealPlanModel {
var delegate:MealPlanProtocol?
var listener:ListenerRegistration?
func getMealPlans(_ starredOnly:Bool = false) {
// Detach any listener
listener?.remove()
// Get a reference to the database
let db = Firestore.firestore()
var query:Query = db.collection("mealPlans")
// If filtering for starred Meal Plans, update the query
if starredOnly {
query = query.whereField("isStarred", isEqualTo: true)
}
self.listener = query.addSnapshotListener({ (snapshot, error) in
// Check for errors
if error == nil && snapshot != nil {
var mealPlans = [MealPlan]()
// Parse documents into mealPlans
for doc in snapshot!.documents {
let m = MealPlan(docID: doc["docID"] as! String, title: doc["title"] as! String, ingredientsProduce: doc["ingredientsProduce"] as! [String], ingredientsProtein: doc["ingredientsProtein"] as! [String], ingredientsSpices: doc["ingredientsSpices"] as! [String], ingredientsOther: doc["ingredientsOther"] as! [String], isStarred: doc["isStarred"] as! Bool)
mealPlans.append(m)
}
// Call the delegate and pass back the notes in the main thread
DispatchQueue.main.async {
self.delegate?.mealPlansRetrieved(mealPlans: mealPlans)
}
}
})
This is what I can't figure out:
My project was building fine with this code
Then I added a new document in Firestore with the same keys
App started crashing
I deleted that document from Firestore (so going back to where I was at (1) when it worked) and the project continued to crash
The error I'm getting is: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value. The error is marked at ingredientsProduce: doc["ingredientsProduce"] as! [String] from my code above.
I couldn't find any typos and the keys all have values in Firestore. Also, everything was working fine before I added/deleted the new document, so it seems like nothing has changed since it last worked. I cleared my build folder and quit/reopened Xcode as well.
Anyone know what might be happening?
Well you are force unwrapping an optional value hence your app is crashing when it turns out to be nil.
doc["ingredientsProduce"] as! [String] // as! means force cast it to array of strings in your example
If the value of ingredientsProduce is an optional you can't force unwrap it and expect it not to crash when it's nil.
Example of safe unwrapping
if let myValues = doc["ingredientsProduce"] as? [String] {
// safe to use myValues
_ = myValues.map { print($0) }
}
If I have
class Info {
var name: String?
}
class User {
var info: Info?
}
class WrappedClass {
var user: User = User()
}
let nameKeyPath = \WrappedClass.user.info?.name //Gets me KeyPath
let referencedNameKeyPath = \WrappedClass.user.info!.name //Gets me ReferenceWritableKeyPath
nameKeyPath gets me a KeyPath which I can't later on use to modify the name value, but if I force unwrap it I get a ReferenceWritableKeyPath which is what I'm after.
Unfortunately using referencedNameKeyPath with a nil value along the line expectedly crashes, due to unexpectedly finding nil.
My question is is there a way to convert the KeyPath to a ReferenceWritableKeyPath or somehow unwrap it along the way?
You can also use optional chaining on keypaths. Create two keypaths one for user and the other one for name in info.
let infoKeyPath = \WrappedClass.user.info
let nameKeyPath = \Info.name
Now, use optional chaining with keypath and it will yield String? as the result.
let name = wrappedInstance[keyPath: infoKeyPath]?[keyPath: nameKeyPath]
Try having the key path as a computed optional variable. Like that:
class WrappedClass {
var user: User = User()
var nameKeyPath: ReferenceWritableKeyPath<WrappedClass, String?>? {
guard let _ = user.info else { return nil }
return \WrappedClass.user.info!.name
}
}
You still end up with the force unwrap notation but it should not cause any issues since you specifically guard for it.
That way you can use the computed key path in a safe and convenient way:
let instance = WrappedClass()
if let nameKeyPath = instance.nameKeyPath {
instance[keyPath: nameKeyPath] = "Nikola"
}
This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 5 years ago.
Hey I'm trying to use Yelp's Review API and am having trouble structuring/writing the code necessary to display the different Yelp Star Ratings. I have no problem getting the response (it's successful). Yelp has provided image assets of all their different star ratings (5, 4.5, 4 etc. stars). Because the rating response is as a Double, I converted that into a String value. As for knowing which to call, I created an enum class so that it knows which image name to use. Using that name, I can then use it to find the image asset I need.
Now that I structure the code this way, my app crashes. Xcode will build it but upon opening the app, it crashes.
Enum class:
import Foundation
import UIKit
enum Rating: String {
case five = "regular_5"
case fourAndAHalf = "regular_4_half"
case four = "regular_4"
case threeAndAHalf = "regular_3_half"
case three = "regular_3"
case twoAndAHalf = "regular_2_half"
case two = "regular_2"
case oneAndAHalf = "regular_1_half"
case one = "regular_1"
case zero = "regular_0"
}
Yelp Client Service class:
import Foundation
import Alamofire
import SwiftyJSON
class YelpClientService {
static func getReviews(url: String, completionHandler: #escaping ([Review]?)-> Void)
{
let httpHeaders: HTTPHeaders = ["Authorization": "Bearer \(UserDefaults.standard.string(forKey: "token") ?? "")"]
//removing diacritics from the URL
if let requestUrl = URL(string: url.folding(options: .diacriticInsensitive, locale: .current))
{
Alamofire.request(requestUrl, encoding: URLEncoding.default, headers: httpHeaders).responseJSON { (returnedResponse) in
let returnedJson = JSON(with: returnedResponse.data as Any)
let reviewArray = returnedJson["reviews"].array
print(reviewArray as Any)
var reviews = [Review]()
for review in reviewArray! {
let userName = review["user"]["name"].stringValue
let ratingDouble = review["rating"].doubleValue
let rating = String(ratingDouble)
let text = review["text"].stringValue
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let timeCreated = formatter.date(from: review["time_created"].stringValue)
let url = review["url"].stringValue
let review = Review(rating: Rating(rawValue: rating)!, userName: userName, text: text, timeCreated: timeCreated!, url: url)
reviews.append(review)
}
completionHandler(reviews)
}
}
else
{
print("invalid url")
completionHandler(nil)
}
}
}
Func in View Controller thats displaying the Star:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reviewCell", for: indexPath) as! ReviewCell
let review = reviewList[indexPath.row]
print(review.userName)
cell.userName.text = review.userName
cell.reviewText.text = review.text
cell.yelpStars.image = UIImage(named: review.rating.rawValue)
//cell.date.text = review.timeCreated
return cell
}
The error when I build is: fatal error: unexpectedly found nil while unwrapping an Optional value.
I'm not sure what went wrong. Is it correct of me to instantiate rating as a Rating type? Should I keep it String?
I realize this is long code but I hope someone can help! Thank you!
I am sure it would crash. The way you have written it. let ratingDouble = review["rating"].doubleValue you are expecting double. It would be 0, 4.5, 3.0 etc. Which would get converted to string "0","4.5" "3.0" etc.Then you try to initialise rating with Rating(rawValue : rating), Rating enum does not have these raw values as "0", "4.5" etc, so nil will be returned. You are force unwrapping it with '!", no doubt its crashing.
You will need to format your enum like this
enum Rating: String {
case five = "5.0"
case fourAndAHalf = "4.5"
case four = "4.0"
case threeAndAHalf = "3.5"
case three = "3.0"
case twoAndAHalf = "2.5"
case two = "2.0"
case oneAndAHalf = "1.5"
case one = "1.0"
case zero = "0.0"
getImageName()-> String {
switch self {
case five:
return "ImageNameForFive"
case fourAndHalf:
return "ImageNameForFourAndHalf.
......
}
}
}
and change
let rating = String(ratingDouble)
to
let rating = String.init(format: "%.1f", ratingDouble)
The error fatal error: unexpectedly found nil while unwrapping an Optional value. is thrown when Swift is unable to do an action usually when the targets are nil, empty, non-existent or undefined.
If a value could potentially be nil, empty, non-existent or undefined; it is known as an optional value. In order to use these values in our code, we must unwrap them. If the value is either nil, empty, non-existent or undefined, our app would most likely crash if it was not unwrapped safely.
To unwrap an object safely in swift we can either use if let or a guard statement. The code is written inside of this only runs if the object is not null.
It's good practice to safely unwrap all your objects in swift to prevent crashes. An example can be found below:
Safe Unwrapping
// initalize a string that may be nil (an optional)
var string: String? = nil
// create a random number between 0-2
let randomNum:UInt32 = arc4random_uniform(3)
// create a switch to set the string value based on our number
switch (randomNum) {
case 0:
string = "Some String"
default:
break
}
// attempt to print out our string
// using a guard statement
guard let string = string else {
// handle if string is null
return
}
// print the string from the guard
print(string)
// using if let
if let string = string {
print(string)
} else {
// handle string is null
}
Unsafe Unwrapping
// initalize a string that may be nil (an optional)
var string: String? = nil
// create a random number between 0-2
let randomNum:UInt32 = arc4random_uniform(3)
// create a switch to set the string value based on our number
switch (randomNum) {
case 0:
string = "Some String"
default:
break
}
// attempt to print our string by forcefully unwrapping it even if it is null causing a crash if it is null
print(string!)
So you can see the difference, in the second one the app would crash with the same error you are getting as it failed to unwrap an optional value in the event the random number is not 0.
It is possible to safely unwrap an object without using if let or guard. This is known as an inline conditional which is basically an if/else clause but quicker.
Inline Conditionals
// if the string is null, it will print the value beside the two `??`
print(string ?? "This is what is printed if the string is nil")
So now that you have all this knowledge, you can go ahead and take a look at your code to see if you are forcefully unwrapping any of your values. A hint is that you use the ! to do this.
Also, the enum that you made takes string values like "half" not double values even if it is a string like '0.5". So it could also crash
Some examples I picked out that may cause the crash are:
for review in reviewArray!
review["rating"].doubleValue
Rating(rawValue: rating)!
timeCreated!
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 ?? "")
}
While I try to pass it to temporary variables it doesn't seem to happen.
Although there are no errors while building the app, once I try to enter a value for "rateOfPaddy", it fails, citing "fatal error: unexpectedly found nil while unwrapping an Optional value"
Please let me know if I'm doing anything wrong, either related to Swift or Eureka?
form +++ Section()
<<< DateTimeRow() {
$0.tag = "RecordDateTag"
$0.title = "Date"
$0.value = NSDate()
}.cellSetup { cell, row in
cell.textLabel?.textColor = UIColor.blackColor()
}.onCellHighlight { _ in
if let dateInput = formInput["RecordDateTag"] as? String {
self.dateInputValue = dateInput
}
}.onCellUnHighlight { _ in
if let dateInput = formInput["RecordDateTag"] as? String {
self.dateInputValue = dateInput
}
}
I used .onChange callback to check and pass the information to local variables, which was of no use. .onCellHighlight and .onCellUnHighlight combination didn't do the trick either!!
Try calling values function as documented here
You can create a method like below and call it from onChange callbacks
func updateValues() {
let allFormData = formInput.values()
if let dateInput = allFormData["RecordDateTag"] as? String {
self.dateInputValue = dateInput
}
}
The error "fatal error: unexpectedly found nil while unwrapping an Optional value" means that you are trying to unwrap an optional that has nil as a value.
Verify that every formInput[KEY] has a value of the type you expect before forcing the unwrap with the as!
You could benefit from the Optional Binding
if let value = formInput["Some"] as? Int
{
//Value exist and is an Int
}
else
{
print("Not an Int")
}
For More references:
Swift Type Casting
Swift Optionals