fatal error: unexpectedly found nil while unwrapping an Optional value: Swift, Core Data

637 views Asked by At

I am getting error on the line: let indexPath = self.menuTable.indexPathForSelectedRow()!. Seems that I am not getting a value from indexPathForSelectedRow. I am parsing from a CSV file into Core Data. Not sure if it matters. I am new to coding, so not sure if I am missing something obvious.

import UIKit
import CoreData

class MenuTableViewController: UITableViewController {

    @IBOutlet var menuTable: UITableView!
    private var menuItems:[MenuItem] = []
    var fetchResultController:NSFetchedResultsController!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Load menu items from database
        if let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext {
            let fetchRequest = NSFetchRequest(entityName: "MenuItem")
            var e: NSError?
            menuItems = managedObjectContext.executeFetchRequest(fetchRequest, error: &e) as! [MenuItem]
            if e != nil {
                println("Failed to retrieve record: \(e!.localizedDescription)")
            }
        }

        // Make the cell self size
        self.tableView.estimatedRowHeight = 66.0
        self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.layoutIfNeeded()
    }

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

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // Return the number of sections.
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return menuItems.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = menuTable.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MenuTableViewCell

        // Configure the cell...
        cell.nameLabel.text = menuItems[indexPath.row].name
        cell.detailLabel.text = menuItems[indexPath.row].detail
//        cell.priceLabel.text = "$\(menuItems[indexPath.row].price as! Double)"

        return cell
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    {
        self.performSegueWithIdentifier("showFront", sender: self)

    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
        if (segue.identifier == "showFront")
        {
            var upcoming: CardFrontViewController = segue.destinationViewController as! CardFrontViewController

            let indexPath = self.menuTable.indexPathForSelectedRow()!

            let titleString = menuItems[indexPath.row].name

            upcoming.titleStringViaSegue = titleString

            self.menuTable.deselectRowAtIndexPath(indexPath, animated: true)

        }
    }

}
3

There are 3 answers

2
Charles A. On BEST ANSWER

Since you have an implementation of tableView:didSelectRowAtIndexPath: and the cell is connected to the segue in the storyboard, the segue is happening twice. The second time the segue is performed there would be no selection because you deselect it during the first segue. You can fix this issue by deleting your implementation of tableView:didSelectRowAtIndexPath: or by creating the segue in the storyboard with the view controller itself as the source instead of the cell and leaving your manual invocation of the segue.

2
Godlike On

I don't know if this is the problem but why are u using self as sender if u need the indexPath?

Try:

 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    {
        self.performSegueWithIdentifier("showFront", sender: indexPath)

    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
        if (segue.identifier == "showFront")
        {
            var upcoming: CardFrontViewController = segue.destinationViewController as! CardFrontViewController


            let titleString = menuItems[indexPath.row].name

            upcoming.titleStringViaSegue = titleString

            self.menuTable.deselectRowAtIndexPath(indexPath, animated: true)

        }
    }
2
dehlen On

I see you are using a UITableViewController. In a UITableViewController a UITableView is automatically created for you with the needed outlets. You can access it in code via self.tableView. My guess is that you do not connected the IBOutlet for your UITableView called menuTable. So the optional which is nil while unwrapping is not the indexPath but the UITableView.

Fix: Delete your IBOutlet and everywhere you use the menuTable variable and use self.tableView instead.