How to check if Optional is not nil and property is true in one expression?
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
}
Swift: Testing optionals for nil
In Xcode Beta 5, they no longer let you do:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
This produces an error:
does not conform to protocol 'BooleanType.Protocol'
You have to use one of these forms:
if xyz != nil {
// Do something using `xyz`.
}
if let xy = xyz {
// Do something using `xy`.
}
Checking the value of an Optional Bool
With optional booleans it's needed to make the check explicit:
if boolean == true {
...
}
Otherwise you can unwrap the optional:
if boolean! {
...
}
But that generates a runtime exception if boolean is nil
- to prevent that:
if boolean != nil && boolean! {
...
}
Before beta 5 it was possible, but it has been changed as reported in the release notes:
Optionals no longer implicitly evaluate to true when they have a value and false when they do not, to avoid confusion when working with optional Bool values. Instead, make an explicit check against nil with the == or != operators to find out if an optional contains a value.
Addendum: as suggested by @MartinR, a more compact variation to the 3rd option is using the coalescing operator:
if boolean ?? false {
// this code runs only if boolean == true
}
which means: if boolean is not nil, the expression evaluates to the boolean value (i.e. using the unwrapped boolean value), otherwise the expression evaluates to false
I am getting a warning comparing my OPTIONAL value to not-nil will always return true
Just remove the entry != nil
clause and it will work as you require. The if let
statement that proceeds it performs the not-nil check already.
guard let entry = entryForEdit else {
return
}
Java Optional if object is not null - returns the method result, if null - returns default value
A few forms:
long lastPollTime = Optional.ofNullable(object).map(o -> o.getTime()).orElse(0L);
long lastPollTime = Optional.ofNullable(object).map(YouObjectClass::getTime).orElse(0L);
long lastPollTime = Optional.ofNullable(object).isPresent() ? object.getTime() : 0;
long lastPollTime = object != null ? object.getTime() : 0;
Of these, the last one, which doesn't use Optional (and therefore doesn't strictly answer your question!) is simpler to read and has fewer runtime overheads, and so should be preferred.
Arguably, it's even simpler if you reverse the options:
long lastPollTime = object == null ? 0 : object.getTime();
... although you might prefer to have the default last -- it's a matter of personal taste.
If you really can't use ternary operators, and you're doing this a lot, you could write your own utility method:
public <T,U> U mapWithFallback(T obj, Function<T,U> function, U fallback) {
if(obj == null) {
return fallback;
} else {
return function.apply(obj);
}
}
... callable as:
long lastPollTime = mapWithFallback(object, o -> o.getTime(), 0);
... or make a complete mockery of your no-ternaries check using:
public <T,U> U ifElse( Supplier<Boolean> a, Supplier<U> ifTrue, Supplier<U> ifFalse) {
if(a.get()) {
return ifTrue.get();
} else {
return ifFalse.get();
}
}
long lastPollTime = ifElse( () -> object == null, () -> object.getTime(), () -> 0);
It's in even better taste to avoid null references altogether, so that this kind of check isn't needed -- for example using the Null Object pattern.
... or by writing methods that return Optional
rather than potential nulls. Optional
is a great class; use it. Just don't convert something to Optional
purely so you can immediately check whether it's empty.
What's the difference between if nil != optional … and if let _ = optional …
After optimization, the two approaches are probably the same.
For example, in this case, compiling both the following with swiftc -O -emit-assembly if_let.swift
:
import Darwin
// using arc4random ensures -O doesn’t just
// ignore your if statement completely
let i: Int? = arc4random()%2 == 0 ? 2 : nil
if i != nil {
println("set!")
}
vs
import Darwin
let i: Int? = arc4random()%2 == 0 ? 2 : nil
if let _ = i {
println("set!")
}
produces identical assembly code:
; call to arc4random
callq _arc4random
; check if LSB == 1
testb $1, %al
; if it is, skip the println
je LBB0_1
movq $0, __Tv6if_let1iGSqSi_(%rip)
movb $1, __Tv6if_let1iGSqSi_+8(%rip)
jmp LBB0_3
LBB0_1:
movq $2, __Tv6if_let1iGSqSi_(%rip)
movb $0, __Tv6if_let1iGSqSi_+8(%rip)
leaq L___unnamed_1(%rip), %rax ; address of "set!" literal
movq %rax, -40(%rbp)
movq $4, -32(%rbp)
movq $0, -24(%rbp)
movq __TMdSS@GOTPCREL(%rip), %rsi
addq $8, %rsi
leaq -40(%rbp), %rdi
; call println
callq __TFSs7printlnU__FQ_T_
LBB0_3:
xorl %eax, %eax
addq $32, %rsp
popq %rbx
popq %r14
popq %rbp
retq
Perform assignment only if right side is not nil
A single expression with the same effect as your code is
funcThatReturnsOptional().map { object.nonOptionalProperty = $0 }
but your code is definitely better readable.
Here the map()
method of Optional
is used and the closure is
executed only if the function does not return nil
.
How to check object is nil or not in swift?
If abc
is an optional, then the usual way to do this would be to attempt to unwrap it in an if statement:
if let variableName = abc { // If casting, use, eg, if let var = abc as? NSString
// variableName will be abc, unwrapped
} else {
// abc is nil
}
However, to answer your actual question, your problem is that you're typing the variable such that it can never be optional.
Remember that in Swift, nil
is a value which can only apply to optionals.
Since you've declared your variable as:
var abc: NSString ...
it is not optional, and cannot be nil
.
Try declaring it as:
var abc: NSString? ...
or alternatively letting the compiler infer the type.
Related Topics
What's The Difference Between [String] VS. [(String)]
Get Output Frames Failed, State 8196
Sbdata Is Wrong When Sbvalue Comes from a Swift Dictionary
What Does an Underscore "_" Mean in Swift
Save/Copy a File from Bundle to Desktop Using Nssavepanel
Navigationlink Inside .Searchable Does Not Work
Make Tabview Background Transparent
Difference Between @Propertydelegate and @Propertywrapper
Convert from Nsdictionary to [String:Any]
Difference When Declaring Swift Protocol Using Inheritance from Another Protocol or Using Where Self
Does Cocoa Connection Binding to Nstoolbaritem Prevent Deinitializing
Why Is Swift Counting This Grapheme Cluster as Two Characters Instead of One
Why Do I Get Source Kit Service Terminated Error
Enum Named 'Type' in Nested Class Fails
Swift Switch Case Compiler Error
No Exact Matches in Call to Instance Method Error Message in Swift