0

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)
        }

    }
}

}

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 4
    You posted way too much code here to be useful. Your issue is that you force unwrap EVERYTHING from the snapshot key-value store. If any of those values does not exist then as! String will crash by definition. You need to conditionally unwrap or nil coalesce those values. – Dare Sep 09 '16 at 15:03
  • @Dare. After getting this error, I have deleted all items in the database. Is it the reason? – Đoàn Thanh An Sep 09 '16 at 15:23
  • Absolutely could be. if snapshot.value!["eventID"] or any other accessor there == nil, then nil as! String will crash. Using ! in Swift essentially means "I swear that this value absolutely cannot possibly be nil no matter what." if it is, then you "unexpectedly found nil while unwrapping an Optional value" – Dare Sep 09 '16 at 15:26

1 Answers1

0

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.

Dare
  • 2,497
  • 1
  • 12
  • 20