Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if Optional is not nil and property is true in one expression?

Tags:

swift

Using Swift, I have an NSStatusItem, and when I click it, I want to check if an NSWindow is visible. If it is, hide it, if it isn't, call a function to show the NSWindow.

My NSWindow is a class property in my app delegate, var window: NSWindow?. In my method which responds to the clicking of the NSStatusItem, I am trying to use Optional Chaining to do the following:

if self.window?.visible {
    self.window!.orderOut(self) // or self.window?.orderOut(self), same behavior
}
else {
    displayWindow()
}

However, if window is not nil, it goes into the if block every time. If window is nil, it goes into the else block every time. In other words, this doesn't appear to work. I cannot check if window is not nil and if window is visible in one expression. (I figured this was an obvious place to use Optional Chaining.)

I tried this, just to see what would happen:

if self.window!.visible {
    self.window!.orderOut(self)
}
else {
    displayWindow()
}

Which works if window is not nil. window is hidden at first, so it hits the else block and shows the window. The next time the method is called, window is visible, so it does the else block. And so on. Exactly what I want, except I cannot check if window is nil. If it is nil, I get the obvious crash "fatal error: Can't unwrap Optional.None"

The following allows me to check if window is nil, and then check if it is visible:

if let win = self.window {
    if win.visible {
        win.orderOut(self)
    } else {
        displayWindow()
    }
}
else {
    NSLog("self.window == nil")
}

However, this is wordy and I really think I should be able to do the first way. Do I really have to do it this third way? Or am I correct in assuming the first case not working is a bug?

EDIT: this way also works:

if self.window && self.window!.visible {
    self.window?.orderOut(self)
}
else {
    displayWindow()
}

But again, isn't Optional Chaining meant to replace this kind of thing?

like image 625
nickjwallin Avatar asked Oct 15 '25 17:10

nickjwallin


1 Answers

Edit:

Cezar's solution (first comment below) turned out to be much more correct:

self.window?.visible == true

There is a serious flaw with my solution below. If self.window is nil, it will try to unwrap nil and crash.

--Old Answer--

As mentioned in my comment:

When you use Optional Chaining, the returned value is always an Optional. That means self.window?.visible returns Bool?. And since it always exists when window is not nil, it will pass the check.

This is explained in the Swift book section on Optional Chaining. It makes sense because when you use Optional Chaining, the return value always has a chance to return nil, and that doesn't depend on the final value in the "chain".

Note: The above is still true, but the following suggestion was terrible :[

So your desired syntax is:

(self.window?.visible)!

Here's some code for you to paste into a Playground to play with this behavior:

import Foundation
class a {
    let t = true;
    let f = false;
}

class b {
    var A:a?
}

let B = b()
B.A = a()

if B.A?.f == true {
    println("true")
}
else {
    println("false") // prints False
}
like image 108
Jack Avatar answered Oct 18 '25 07:10

Jack



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!