Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does UILabel.text result in “fatal error: unexpectedly found nil while unwrapping an Optional value”?

I've read several answers to this question and have tried all recommendations with no success. I'm fairly new to swift and am building an app with Swift, PHP and MySQL. I'm receiving the error after the user has logged in to the app and the system should be displaying the username via a label using UILabel.text. The error is occurring on setting a value to the UILabel.text variable. My code is included below. I've tried to hardcode values on other pages and am getting this error throughout my project.

import UIKit

class HomeViewController: UITabBarController {

    @IBOutlet var usernameLbl: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // set global variables
        let username = (user!["username"] as AnyObject).uppercased

        // label values
        print(usernameLbl ?? username!)
        usernameLbl.text = username
    }
}

I'm accessing the HomeViewController programmatically. The app uses a tab bar and the first page of it is Home. The code is from a course I'm taking on Udemy. Here is how I'm accessing Home:

// func to pass to home page or to tabBar
func login() {

    // refer to our Main.storyboard
    let storyboard = UIStoryboard(name: "Main", bundle: nil)

    // store our tabBar Object from Main.storyboard in tabBar var
    let tabBar = storyboard.instantiateViewController(withIdentifier: "tabBar")

    // present tabBar that is storing in tabBar var
    window?.rootViewController = tabBar

}
like image 647
techgirl Avatar asked Apr 14 '17 01:04

techgirl


1 Answers

You might want to follow best practices and avoid the use of ! as much as possible.

The error you've got happens when you try to access a value or reference stored in an optional that does not contain any value (i.e., it is nil).

In your case, if usernameLbl is nil, usernameLbl.text will crash your app (Think "null pointer exception" in Java, perhaps?).

It is very common to define outlests as:

@IBOutlet weak var label: UILabel!

...instead of the safer:

@IBOutlet weak var label: UILabel?

...because the first one allows you to access its properties without using the ? (i.e. label.text vs. label?.text). But there's an implicit assumption that the label is not nil: the ! by itself does nothing to prevent this (it only silences the compiler, telling it "I know what I'm doing, trust me!").

That shouldn't be a problem as long as you only access it after viewDidLoad() and your outlets are proerly connected in Interface Builder/storyboard, because in that case it will be guaranteed to not be nil.

My guess is that you forgot to hook up the outlet to your label.

Here is a tutorial on storyboards in case it helps.


The whole reason outlets need to be defined as optionals (implicitly unwrapped ! or "standard" ?) is that in Swift, all properties must have a value by the time the instance is initialized (actually, even before calling the super class initializer if that applies).

For view controllers, instance initialization happens before the subviews can be initialized and assigned to the properties/outlets. That happens in the method loadView(), which is called lazily (only just before the view is actually needed for display). So by making all subviews optional (and variable, not constant), they can have the temporary "value" of nil by the time the initializer completes execution (thus satisfying Swift's rules).


Edit: If your outlet is still nil at runtime even though it is connected in interface builder, you can at least try to intercept any code resetting it and see what's going on, with a property observer:

@IBOutlet weak var label: UILabel! {
    didSet {
        if label == nil {
            print("Label set to nil!") 
            // ^ SET A BREAKPOINT IN THIS LINE
        }
    }
}
like image 161
Nicolas Miari Avatar answered Sep 19 '22 08:09

Nicolas Miari