I understand what optional are in Swift but I just encountered a ”Double Wrapped Optional’, where if I don’t use two '!'
Xcode gives an complier error
Value of optional type 'String?' not unwrapped; did you mean to use '!' or ‘?'?
I have the following code, where app
is of type NSRunningApplication
.
let name: String = app.localizedName!
Why should I have to use two !
? Isn’t one enough to unwrap the variable because it is of type var localizedName: String?
.
Context:
Xcode want me to use let name: String = app.localizedName!!
, otherwise it gives the compiler error above.
The app
variable is defined as follow:
var apps = NSWorkspace().runningApplications.filter{$0.activationPolicy == NSApplicationActivationPolicy.Regular}
for app in apps{
//code posted above
…
}
So I know that app
is not an optional and will always have a value, nor is it an optional application.
P.S. Is there a way to define type when using fast enumeration? Like for Foo(app) in apps
where apps = [AnyObject]
.
You can unwrap optionals in 4 different ways: With force unwrapping, using ! With optional binding, using if let. With implicitly unwrapped optionals, using !
Even though Swift isn't sure the conversion will work, you can see the code is safe so you can force unwrap the result by writing ! after Int(str) , like this: let num = Int(str)! Swift will immediately unwrap the optional and make num a regular Int rather than an Int? .
However there is another data type in Swift called Optional, whose default value is a null value ( nil ). You can use optional when you want a variable or constant contain no value in it. An optional type may contain a value or absent a value (a null value). Non technically, you can think optional as a shoe box.
The problem is that NSWorkspace().runningApplications
returns an
array of AnyObject
which has to be cast to an array of
NSRunningApplication
:
let apps = NSWorkspace().runningApplications as! [NSRunningApplication]
let filteredApps = apps.filter {
$0.activationPolicy == NSApplicationActivationPolicy.Regular
}
for app in apps {
let name: String = app.localizedName!
}
Here's why: app
is of type AnyObject
(id
in Objective-C), and doing any lookup on AnyObject
introduces a layer of optionality because of the possibility that the method doesn’t exist on the object. localizedName
is itself Optional, so you end up with two levels of optional: the outer level is nil if the object doesn’t respond to localizedName
, and the inner is nil if 'localizedName' is nil.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With