As already explained in the other answers, comparing the optional
NSURL?
against true
or false
is not what you want, and you should
use optional binding instead.
But why does it compile at all? And how can the result be interpreted?
In NSURL(string: urlString) == true
, the left-hand side has the type
NSURL?
, and NSURL
is a subclass of NSObject
.
There is a ==
operator taking two optional operands:
public func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool
The compiler uses the implicit conversion of Bool
to NSNumber
to make that compile. So your code is equivalent to
if NSURL(string: urlString) == NSNumber(bool: true)
and that will always be false, and
if NSURL(string: urlString) != NSNumber(bool: false)
will always be true, simply because the left-hand side is not a
number.
Here is a demonstration of the effect:
func foo(x: NSObject?) {
print(x == true, x == false)
}
foo(NSNumber(bool: true)) // true, false
foo(NSNumber(bool: false)) // false, true
foo(NSObject()) // false, false !!!
The last case is what you observed: Both x == true
and x == false
return false
.
For classes not inheriting from NSObject
it would not compile:
class A { }
let a: A? = A()
if a == true { } // cannot convert value of type 'A?' to expected argument type 'Bool'
Remark: This is another argument for not comparing boolean values
against true
or false
, i.e.
if a == true && b == false { ... }
is better written as
if a && !b { ... }
Applied to your case, you would get a compiler error indicating
the problem:
let urlString = "http://www.websitethatlinkstoJSONfile.com"
if NSURL(string: urlString) { }
// error: optional type '_' cannot be used as a boolean; test for '!= nil' instead