Seong Lee
Seong Lee

Reputation: 10520

Swift 2.1 - IBOutlet property is nil in custom UITableViewCell class

I believe creating a custom class to configure a table cell is a standard practice of iOS development. I apply this practice to my app as well but I'm having some issue with it.

I have two tableviews - one for each ViewController - that their cell is using the same custom cell class.

CustomCellClass

import UIKit

class RecipeCategoryCell: UITableViewCell {

    @IBOutlet weak var recipeCategoryLabel: UILabel!
    @IBOutlet weak var chooseCategoryLabel: UILabel!

    //...

    func configureCell(recipe: Recipe) {
        let category = recipe.category as? RecipeCategory
        recipeCategoryLabel.text = category!.name
    }

    func configureNewCell(category: RecipeCategory) {
        recipeCategoryLabel.text = category.name
    }

    // re-configure receiver's viewcontroller cell with selected category value
    func configureSelectedCategoryCell(selectedCategory: String) {        
        recipeCategoryLabel.text = selectedCategory
    }

    // configure all available category names in the sender's viewcontroller
    func configureChooseCategoryCell(category: RecipeCategory) {
        chooseCategoryLabel.text = category.name
    }
}

@IBOutlet weak var recipeCategoryLabel: UILabel! belongs to a receiver viewController and @IBOutlet weak var chooseCategoryLabel: UILabel! belongs to a sender viewController

I have an issue at the 3rd function at this line recipeCategoryLabel.text = selectedCategory that Xcode says

fatal error: unexpectedly found nil while unwrapping an Optional value

I don't have this issue on other functions that uses the same IBOutlet recipeCategoryLabel but only the function configureSelectedCategoryCell() that re-configures receiver ViewController cell with selected category value. So I can say for certainty that this is not a connection problem with storyboard.

I suppose this is happening because the same IBOutlet property is used in multiple places. But the thing is that, I have to use the same property so I can set default value, update the selected value, set previously persisted value on the same label.

I don't know if my explanation is clear enough but basically I cannot set the table cell label of receiver's ViewController with the selected category value that was passed from the sender's ViewController.

UPDATE

enter image description here

And configureSelectedCategoryCell() is called in the receiver's ViewController extension:

extension CreateRecipeVC: RecipeCategoryTableVCDelegate {

func categoryController(controller: RecipeCategoryTableVC, didSelectCategory category: String) {

    selectedCategory = category

    self.navigationController?.popViewControllerAnimated(true)

    let cell = RecipeCategoryCell()
    cell.configureSelectedCategoryCell(selectedCategory)

}

}

Upvotes: 0

Views: 615

Answers (1)

Manuel
Manuel

Reputation: 15042

The cell's outlets are not instantiated at the point when you try to access them in configureSelectedCategoryCell.

As I understand the cells are designed in Interface Builder, so the outlets of the cell object cell are missing the references to the controls in Interface Builder.

After a category is selected you should

  1. Update the tableView's data source
  2. Reload the tableView's items

Something like this:

func categoryController(controller: RecipeCategoryTableVC, didSelectCategory category: String) {

    selectedCategory = category
    self.navigationController?.popViewControllerAnimated(true)

    tableViewDataSource[selectedItemIndex].selectedCategory = selectedCategory
    tableView.reloadData()
}

Then in the table view data source delegate:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

   let cell = tableView.dequeueReusableCellWithIdentifier("YourCellIdentifer") as! RecipeCategoryCell
   cell.configureSelectedCategoryCell(tableViewDataSource[indexPath.row].selectedCategory)
   return cell
}

Side notes:

It is legit to connect one IBOutlet to multiple controls in the storyboard.

As precaution I suggest to remove the force unwrapping of an optional in configureCell, e.g.

func configureCell(recipe: Recipe) {
    if let category = recipe.category as? RecipeCategory {
       recipeCategoryLabel.text = category.name
    }
}

Upvotes: 1

Related Questions