Reputation: 48466
I understand that in Swift, if I define
var opt:String? = "Optional"
I will get an error if I attempt
opt.isEmpty
since opt
is of type String?
which does does not have an isEmpty
method. And I thought that I understood that
opt?.isEmpty
does not produce an error because opt?
unwraps (any non-nil
) opt
, resulting in a String
, which does have an isEmpty
method. But
opt?
on its own results in a String?
and not a String
.
Is ?.
a different operator from ?
followed by .
?
Try
(opt?).isEmpty
and get a suggestive error.
Upvotes: 0
Views: 321
Reputation: 122439
But opt? on its own results in a String? and not a String.
Yes. According to the Swift language reference, Expressions, Postfix Expressions, Optional-Chaining Expression:
On its own, the postfix ? operator simply returns the value of its argument as an optional.
So putting a ?
by itself at the end of an optional is a complete no-op. It has no effect.
Is ?. a different operator from ? followed by .?
Yes. More specifically, ?
has the optional-chaining effect when used in any "postfix expression", including when followed by ()
(function call), .
(member access), and []
(subscript).
Upvotes: 1
Reputation: 37189
Yes opt?.isEmpty
is different from String?
.It is called optional chaining.From swift programming guide:
You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property, method or subscript if the optional is non-nil. This is very similar to placing an exclamation mark (!) after an optional value to force the unwrapping of its value. The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.
This creates optional as you thinking var opt:String?
Now
opt?.isEmpty //it will not crash if opt is nil
is same as except
opt!.isEmpty //it will crash if opt is nil
if opt!
is nil
than it will not crash at runtime.Optional chaining is used to call long sequences of optional without calling.Every optional chain returns optional i.e opt? returns optional unwraps it and if nil than not call isEmpty else call isEmpty and reutns value.
Also
(opt?).isEmpty
When you are writing above statement it is just optional(not optional of optional) and it fails to unwrap because of braces.So error is showing
$T2?? does not have a member named `isEmpty`
to unwrap it use
(opt?)!.isEmpty
it will return false
Edit: To clarify more
var o1 = opt?
var o2 = ((opt?)?)
is doing nothing in its own it just assign same value to o1
,o2
i.e String?.
to unwrap opt
and o1
,o2
they both are optional and need single !
operator to unwrap it.
Also please do not misunderstood between String?
and opt?
they both are different when ? is used after some type in decleration it makes optional and when ?
used after variable opt
it is used for unwrap in optional chaining and return optional value it is returning
Extra Stuff:
try this to more clarify
(((opt?)?)!).isEmpty //it will unwrap with single !
((((opt?)?)!)?).isEmpty //compiler will show suggestion to remove ?
the below statement makes optional of optional of optional
var opt:String??? = "Optional"
to unwrap
opt!!!.isEmpty
EDIT2
opt?
always return optional but if opt
is defined as String! it is implicit optional
and opt?
will return optional(explicit)
.But if opt
is already optional opt?
will do nothing
From swift programming guide
To put it another way:
If the type you are trying to retrieve is not optional, it will become optional because of the optional chaining. If the type you are trying to retrieve is already optional, it will not become more optional because of the chaining.
Therefore:
If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used. Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
Upvotes: 2