Swift === with nil
It works exactly like you expect:
var s: String? = nil
s === nil // true
The only caveat is that to compare to nil
, your variable must able to be nil
. This means that it must be an optional, denoted with a ?
.
var s: String
is not allowed to be nil
, so would therefore always returns false
when ===
compared to nil
.
Swift nil Any != nil
Think of Any
and Optional<Wrapped>
like boxes.
Any
is an opaque box that can hold anything. You can gleam what's inside by trying to cast it usingas?
.Optional<Wrapped>
is a transparent box. It lets you see that its contents are either a value ofOptional<Wrapped>.some(wrapped)
orOptional<Wrapped>.none()
.
An Optional<Any>
and Any
containing an Optional<Wrapped>
aren't the same thing.
1. x
is a value of Optional<Any>.none
, a.k.a. nil
. nil
gets printed, so that makes sense.
2. type(of: x)
is the type of x
, Optional<Any>
, as we expected.
3. x == nil
is calling an ==
operator of type (T, T) -> Bool
. Since both args need to be the same type, and since x
has a value of Optional<Any>.none
(of type Optional<Any>
), nil
is inferred to be Optional<Any>.none
. The two are equivalent, so we get true
, as expected.
4. y
is a value of type Any
. At compile time, nothing more is known about y
. It just so happens that the value behind hidden by the opaque curtain of Any
is x
. print
is implemented to "see through" Any
instances
, to show you what's really there.
5. type(of: y)
is doing something similar to print
. It's using runtime type information to see exactly what the runtime value stored into y
is. The static type of y
is Any
, but type(of: y)
shows us that the runtime type of its value is Optional<Any>
.
6. y == nil
This is where it gets a little trickier.
The choice of which overload of a function or operator to call is done at compile time, based on the statically known types of the operands. That is to say, operators and functions aren't dynamically dispatched based on the types of their arguments, the way they're dynamically dispatched based on the type of their objects (e.g. the foo
in foo.bar()
).
The overload that's selected here is ==(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool
. You can see its implementation on lines 449-481 of Optional.swift
.
Its left-hand-side operand is Wrapped?
, a.k.a. an Optional<Wrapped>
.
Its right-hand-side operand is _OptionalNilComparisonType
. This is a special type that conforms to ExpressibleByNilLiteral
.
Optional is one type that conforms to ExpressibleByNilLiteral
, meaning that you can write let x: Optional<Int> = nil
, and the compiler could use that protocol to understand that nil
should mean Optional<Int>.none
. The ExpressibleByNilLiteral
protocol exists to allow this behaviour to be extensible by other types. For example, you can imagine a Python interopability framework, where you would want to be able to say let none: PyObject = nil
, which could be passed into Python
and resolve to None
, Python's null type.
What's happening here is that the left hand side (y
, of type Any
), is being promoted to type Any?
. The promoted value has type Optional<Any>.some(old_value_of_y)
. The right hand side, the nil
, is being used to instantiate a value of _OptionalNilComparisonType
, equivalent to calling _OptionalNilComparisonType.init(nilLiteral: ())
.
Thus, your call site is equivalent to:
Optional<Any>.some((Optional<Any>.none) as Any) == _OptionalNilComparisonType(nilLiteral: ()) /*
↑ ↑↖︎_the value of x_↗︎ ↑↑
↑ ↖︎_the value of y _________↗︎↑
↖︎_the value of y after promotion to optional__↗︎ */
According to the implementation, the left side is a some
, the right side is a nil
, and thus they're unequal.
You might say:
Well this is pretty non-obvious behaviour, it's not what I wanted.
To which I would respond:
Don't ignore the compiler errors, they're right on point:
warning: comparing non-optional value of type
Any
tonil
always returnsfalse
Performance based difference between nil and empty string in swift
If I want to choose in between nil and " "
. I will go for nil parameter as nil
is better than sending a empty string as according to me string will be taken as a string even if its of one char
length and nil
is taken as empty which will actually save memory not a big difference. But, in case of 500 UITextFields
yes it matters go for nil
.
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
Does anybody know the rationale behind (nil 0) == true and (nil = 0) == true in Swift?
Optionals are comparable, so they can be sorted, for example. The rules are very simple:
- Any two optionals that are nil compare equal.
- If one of the optionals is nil and the other is not, nil is less than non-nil.
- If both optionals are not nil, then the unwrapped values are compared.
As a consequence, nil equals nil, and nil is less than any non-nil optional.
It has nothing to do with the value 0 that you assigned. Assign -1000, or +100, or whatever you like, and you get the same result.
Swift nil values behaviour
Not exactly, you have to use Optional Chaining. In swift, an instance can only be nil
if it is declared as an "optional" type. Normally this looks like this:
var optionalString : String?
Notice the ?
after the String
That is what makes it possible to be nil
You cannot call a method on that variable unless you first "unwrap" it, unless you use the aforementioned Optional Chaining.
With optional chaining you can call multiple methods deep, that all allow for a nil value to be returned:
var optionalResult = optionalString.method1()?.method2()?.method3()
optionalResult
can also be nil. If any of the methods in the chain return nil, methods after it are not called, instead optionalResult immediately gets set to nil.
You cannot deal directly with an optional value until you explicitly handle the case that it is nil. You can do that in one of two ways:
Force it to unwrap blindly
println(optionalString!)
This will throw a runtime error if it is nil, so you should be very sure that it is not nil
Test if it is nil
You can do this by using a simple if statement:
if optionalString {
println(optionalString!)
}
else {
// it was nil
}
or you can assign it to a scoped variable so that you don't have to forcefully unwrap it:
if let nonoptionalString = optionalString {
println(nonoptionalString)
}
else {
// it was nil
}
How can ı add value to nil object in swift
See inline comments for an explanation of what's going on:
struct NilControl{
var name:String?
}
var k: NilControl? //you've defined k as NilControl? and not assigned it a value yet
print(k) //this will be nil, since k has not been set
k = NilControl() //this sets k to have a value (ie not nil), but its `name` is still nil at this point
k?.name = "name"
print(k?.name) //will print Optional("name")
If you want to do some nil
checking on it before printing the name
, it might look something like this:
k = NilControl(name: "name") //this sets k to have a value & assigns a name
if let k = k, let name = k.name {
print(name)
}
Is checking nil and empty for a set at the same time safe in Swift?
It is perfectly safe as it will execute the second statement only when the first one is true.
It's better to use:
guard let newValue = newValue // First unwrap it
where newValue.count > 0 else { // Then check if the unwrapped value has items
return // If not we don't continue
}
// From this point you don't need to use ? or ! to access newValue anymore
Always try to use safe patterns in your Swift code. To me casting with ! is a code smell and I would always try to replace it with a if let thing = thing or guard let thing = thing statement
Checking for nill equality in custom == operator
Here's the code to make your class Equatable
class ClassXYZ: Equatable {
let uniqueID: String
init(uniqueID: String) {
self.uniqueID = uniqueID
}
}
func ==(left: ClassXYZ, right: ClassXYZ) -> Bool {
return left.uniqueID == right.uniqueID
}
You don't need (and you can't) to explicitly specify that nil == nil
is true
, it is already built into Swift, look
let a: ClassXYZ? = nil
let b: ClassXYZ? = nil
print(a == b) // true
Related Topics
Xcode: Could Not Load Modelio.Framework, Scenekit.Framework, etc
Swift: Deallocate Gamescene After Transition to New Scene
How to Get the Yaw, Pitch, Roll of an Aranchor in Absolute Terms
What's the Best Approach to Prefill Core Data Store When Using Nspersistentcloudkitcontainer
Proper Model for Multiple Alamofire Requests for Multiple Websites
Convert or Cast Object to String
Converting String to Data in Swift 3.0
Giving Physics to Tiles of Sktilemapnode in Xcode 8
Variable P Passed by Reference Before Being Initialized
Swift3:How to Handle Precedencegroup Now Operator Should Be Declare with a Body
Kvo with Shared Nsuserdefaults in Swift
Mkmapview Not Clustering Annotation on Zooming Out Map in Swift
How to Install Package in Xcode via Swift Package Manager
Nsurlsession/Nsurlconnection Http Load Failed (Kcfstreamerrordomainssl, -9802)
Swift Calling Static Methods: Type(Of: Self) VS Explicit Class Name