0

My Swift program is crashing with a fatal error, saying that "Unexpectedly found nil while implicitly unwrapping an Optional value" even with the GUARD statement . Can anyone help to tell me why, and how do I fix it? The code as follows:

var page: Page? {
        didSet{
          guard let unwrappedPage = page else { return }
            NameLabel.text =  unwrappedPage.dishName
            Image.image = UIImage(named: unwrappedPage.imageName)
            contentText.text = unwrappedPage.ingredient
            contentText.text = unwrappedPage.instruction

        }
    }
Ivy
  • 25
  • 2
  • what you are trying to do ? – Jawad Ali Apr 29 '20 at 18:16
  • 1
    if `NameLabel` is nil, while set as IBOutlet non nil... Or `Image`. Or `contentText`. – Larme Apr 29 '20 at 18:23
  • 2
    Possible duplicate of: [What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?](https://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu) – TylerP Apr 29 '20 at 18:43

1 Answers1

-1

The issue is likely that the outlets have not been hooked up by the time you set page, and if these outlets are implicitly unwrapped optionals (with the ! after the type name, e.g. UILabel!), that will result in the error you describe. This problem will manifest itself if, for example, you set page before the view controller in question has been presented and all of the outlets have been hooked up.

So, I’d recommend:

  1. Use optional chaining with your @IBOutlet references so it won’t fail if the outlets haven’t been hooked up yet.

  2. Go ahead and keep your didSet observer on page, if you want, but make sure you also update the controls in viewDidLoad in case page was set before the outlets were hooked up.

For example:

@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var imageView: UILabel!
@IBOutlet weak var ingredientLabel: UILabel!
@IBOutlet weak var instructionLabel: UILabel!

var page: Page? { didSet { updateControls(for: page) } }

override func viewDidLoad() {
    super.viewDidLoad()
    updateControls(for: page)
}

func updateControls(for page: Page?) {
    nameLabel?.text = page?.dishName
    imageView?.image = page.flatMap { UIImage(named: $0) }
    ingredientLabel?.text = page?.ingredient
    instructionLabel?.text = page?.instruction
}

Note, you only need this didSet observer if the page might be set (again) after the view has been presented. If not, the didSet observer is not needed.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • By the way, I’ve renamed the controls to follow the standard conventions (start with lower case letters). Also, I’m assuming you didn’t mean to set and then immediately reset `contentText`. So I assumed you would have different controls for that. – Rob Apr 29 '20 at 19:42