简体   繁体   中英

Swift property observer and nil

I have a property observer code that must modify an iboutlet property:

@IBOutlet weak var canYouGuessLbl: UILabel!

var isNewUser: Bool = false {
    didSet {
        if isNewUser {
            canYouGuessLbl!.layer.zPosition = 5
            canYouGuessLbl!.hidden = false
        } else {
            canYouGuessLbl!.hidden = true  // Error at this line
        }

    }
}

This crashes at runtime because canYouGuessLbl! seems to be nil:

fatal error: unexpectedly found nil while unwrapping an Optional value

I'm not sure about the reason and how to resolve this.

If your problem occur in scenario number one of Antonio's answer then you can solve it by declaring your isNewUser variable as optional and assign value to it on viewDidLoad method after canYouGuessLbl is fully initialized

var isNewUser: Bool! {

    didSet(newValue) {

        if isNewUser != nil && isNewUser! {

            canYouGuessLbl!.layer.zPosition = 5
            canYouGuessLbl!.hidden = false

        } else if isNewUser != nil && !isNewUser! {

           canYouGuessLbl!.hidden = true

        }

    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    isNewUser = false
}

There are a few reasons why canYouGuessLbl could be nil when assigning a new value to isNewUser :

  • isNewUser is assigned a new value before canYouGuessLbl has been initialized (prior to viewDidLoad , such as in an initializer)

  • an outlet has not been defined for canYouGuessLbl (ie the label control in interface builder has not been connected to the property)

  • the view controller in IB is not connected to the implementation class (custom class in identity inspector)

Update - In the first case, you can fix by explicitly checking for not nil:

var isNewUser: Bool = false {
    didSet {
        if canYouGuessLbl != nil {
            if isNewUser {
                canYouGuessLbl.layer.zPosition = 5
                canYouGuessLbl.hidden = false
            } else {
                canYouGuessLbl.hidden = true  // Error at this line
            }
        }
    }
}

Note however that doing that the label won't be updated (because it doesn't exist yet). It just prevents the exception.

Additional note: didSet (and more generally property observers) is not invoked when the property is initialized.

Thanks for your answers guys. It inspired me for this solution:

I had to put the action to perform in a separate function:

    func ifNewUser() {
    if isNewUser! {
        canYouGuessLbl?.layer.zPosition = 5
        canYouGuessLbl?.hidden = false
    } else if !isNewUser! {
        canYouGuessLbl?.layer.zPosition = 5
        canYouGuessLbl?.hideAndDisable()
    }
}

The main problem was with initialization, so first I check this in viewDidLoad:

ifNewUser()

Because the bool value receives its value very early by a segue, It's appropriate to check it first in viewDidLoad after all the variables including the IBoutlets are initialized.

Then for when the user is not declared a new user anymore, I keep the observer, but with call to function:

    var isNewUser: Bool? {
    didSet {
        ifNewUser()
        }
    } 

Does the job.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM