Đoàn Thanh An Đoàn Thanh An - 1 year ago 76
iOS Question

fatal error: unexpectedly found nil while unwrapping an Optional value when load the value from Firebasedatabase

I am pretty new with swift. I tried to finger out myself. I know this is the common question, but I hope I could get help. When I run the application. I got the "fatal error: unexpectedly found nil while unwrapping an Optional value".

import Foundation
import Firebase
import FirebaseDatabase
import FirebaseStorage
import FirebaseAuth

struct TodoItemDatabase {
var eventID: String!
var title: String!
var staff: String!
var location: String!
var starts: String!
var ends: String!
var rpeat: String!
var imageName: String!
var description: String!
var secondPhoto: String!
var ref: FIRDatabaseReference?
var key: String!
var isCompleted: Bool

init (eventID: String!, title: String,staff:String, location: String,starts: String, ends: String, rpeat: String, imageName: String, description: String, secondPhoto: String, key: String = "", isCompleted: Bool){
self.eventID = eventID
self.title = title
self.staff = staff
self.location = location
self.starts = starts
self.ends = ends
self.rpeat = rpeat
self.imageName = imageName
self.description = description
self.secondPhoto = secondPhoto
self.key = key
self.ref = FIRDatabase.database().reference()
self.isCompleted = isCompleted
}
init(snapshot: FIRDataSnapshot){

**//I get the error from here. However, I think the main reason in tableview below**

self.eventID = snapshot.value!["eventID"] as! String
self.title = snapshot.value!["title"] as! String
self.staff = snapshot.value!["staff"] as! String
self.location = snapshot.value!["location"] as! String
self.starts = snapshot.value!["starts"] as! String
self.ends = snapshot.value!["ends"] as! String
self.rpeat = snapshot.value!["rpeat"] as! String
self.imageName = snapshot.value!["imageName"] as! String
self.description = snapshot.value!["description"] as! String
self.secondPhoto = snapshot.value!["secondPhoto"] as! String
self.key = snapshot.key
self.ref = snapshot.ref
self.isCompleted = snapshot.value!["isCompleted"] as! Bool
}
func toAnyObject() -> [String: AnyObject] {
return ["eventid": eventID, "title": title, "staff": staff, "location": location, "starts": starts, "ends": ends, "rpeat": rpeat, "imageName": imageName, "description": description, "secondPhoto": secondPhoto, "isCompleted": isCompleted]
}


}

However, When I run the application, and load the tableview. It appears that error.

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage

var toDoList:[TodoItemDatabase] = [TodoItemDatabase]()

class CurrentEventViewController: UIViewController, UITableViewDelegate {

var databaseRef: FIRDatabaseReference!{
return FIRDatabase.database().reference()
}

var storageRef: FIRStorageReference!

@IBOutlet var toDoListTable: UITableView!

override func viewDidLoad() {
super.viewDidLoad()



}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return toDoList.count

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! myCell
let todoItem = toDoList[indexPath.row]
storageRef = FIRStorage.storage().referenceForURL(toDoList[indexPath.row].imageName)
storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) in

if error == nil {
dispatch_async(dispatch_get_main_queue(), {
if let data = data {
cell.myImageView.image = UIImage(data: data)
}

})
} else {
print(error!.localizedDescription)
}


}
cell.myLabel.text = todoItem.title!

return cell


}


func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

if editingStyle == UITableViewCellEditingStyle.Delete {

let ref = toDoList[indexPath.row]
ref.ref?.removeValue()
toDoList.removeAtIndex(indexPath.row)



toDoListTable.reloadData()
}

}


override func viewDidAppear(animated: Bool) {

toDoListTable.reloadData()

}
override func viewWillAppear(animated: Bool) {
let postRef = FIRDatabase.database().reference().child("posts").queryOrderedByChild("isCompleted").queryEqualToValue(false)
postRef.observeEventType(.Value, withBlock: { (snapshot) in
var newPosts = [TodoItemDatabase]()
for post in snapshot.children{
**// I think the reason is the line after.**
let post = TodoItemDatabase(snapshot: post as! FIRDataSnapshot)
newPosts.insert(post, atIndex: 0)
}
toDoList = newPosts
dispatch_async(dispatch_get_main_queue(), {
self.toDoListTable.reloadData()
})
}) { (error) in
print(error.localizedDescription)
}
}


func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

storageRef = FIRStorage.storage().referenceForURL(toDoList[indexPath.row].imageName)
let storageRef1 = FIRStorage.storage().referenceForURL(toDoList[indexPath.row].secondPhoto)
let itemSelected = toDoList[indexPath.row]
storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) in
if error == nil
{
dispatch_async(dispatch_get_main_queue(), {
if let data = data
{
storageRef1.dataWithMaxSize(1 * 1024 * 1024) { (data1, error) in

if error == nil
{
dispatch_async(dispatch_get_main_queue(), {
if let data1 = data1
{
let detailVC:DetailViewController = self.storyboard?.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
detailVC.titleEvent = itemSelected.title
detailVC.staffEvent = itemSelected.staff
detailVC.locationEvent = itemSelected.location
detailVC.startEvent = itemSelected.starts
detailVC.endEvent = itemSelected.ends
detailVC.repeatEvent = itemSelected.rpeat
detailVC.imageDetail = UIImage(data: data)!
detailVC.descriptionDetail = itemSelected.description
detailVC.secondPhotoEvent = UIImage(data: data1)!
detailVC.key = itemSelected.key
self.presentViewController(detailVC, animated: true, completion: nil)
}
})
}
else
{
print(error!.localizedDescription)
}

}}
})
}
else
{
print(error!.localizedDescription)
}

}
}


}

Answer Source

You need to conditionally unwrap or nil coalesce these values. Force unwrapping the way you are is not safe.

self.eventID = snapshot.value!["eventID"] as! String

should probably be

eventID = snapshot.value?["eventID"] as? String ?? ""

Unfortunately, the compiler loves to suggest force-unwrapping when it encounters optional values. This is almost always a terrible suggestion. You need to get into the habit of handling Optionals gracefully when you encounter .None since Optionals are such an integral part of the Swift language.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download