Uwrapping optionals - Swift 1.2 Xcode 6.4
Firstly, when creating a variable e.g. Santa, please make the first letter lowercase, i.e santa.
To use unwrapped santa in the second if statement, add an exclamation mark, this tells the compiler that you know this variable is not nil.
println("Santa exists! Santa is: \(Santa!)")
You could also use the code below as you have set the contents of the variable Santa to SantaExist as a constant
if let SantaExist = Santa {
println("Santa exists! Santa is: \(SantaExist)") //Santa exists! Santa is: Optional("I am here!)
}
else {
println("Santa is missing! Santa is: \(Santa) or not set")
}
As for optional chaining, this is simply putting a question mark in place of the exclamation mark, so that if it is nil it will "fail gracefully" rather than crash the app.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html#//apple_ref/doc/uid/TP40014097-CH21-ID246
Map and flatMap difference in optional unwrapping in Swift 1.2
(Remark: The answer has been updated to reflect the syntax changes in Swift 3 and later, such as the abolishment of ImplicitlyUnwrappedOptional
.)
Optional.map()
and Optional.flatMap()
are declared as follows (I have omitted the throws/rethrows modifiers which are irrelevant here):
func map<U>(_ transform: (Wrapped) -> U) -> U?
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U?
Let's consider a simplified version of your first example using “map”:
let number: Int? = 1
let res1 = number.map { $0 + 1 }
print(res1) // Optional(2)
number
has the type Int?
and the closure type is inferred as (Int) -> Int
. U
is Int
, and the type of the return value is Int?
. number
is not nil
, so it is unwrapped and passed 1
is passed to the closure. The closure returns 2
and map
returns Optional(2)
. If number
were nil
then the result would be nil
.
Now we consider a simplified version of your second example with “flatMap”:
let number: Int? = 1
let res2 = number.flatMap { $0 + 1 }
print(res2) // Optional(2)
flatMap
expects a closure of type (Wrapped) -> U?
, but { $0 + 1 }
does not return an optional. In order to make it compile, the compiler converts this to
let res2 = number.flatMap { return Optional($0 + 1) }
Now the closure has type (Int) -> Int?
, and U
is Int
again. Again, number
is unwrapped and passed to the closure. The closure returns Optional(2)
which is also the return value from flatMap
. If number
were nil
or if the closure would return nil
then the result would be nil
.
So there is indeed no difference between these invocations:
let res1 = number.map { $0 + 1 }
let res2 = number.flatMap { $0 + 1 }
However that is not what flatMap
is meant for. A more realistic example would be
func foo(_ s : String?) -> Int? {
return s.flatMap { Int($0) }
}
print(foo("1")) // Optional(1)
print(foo("x")) // nil (because `Int($0)` returns nil)
print(foo(nil)) // nil (because the argument is nil)
Generally, map
takes a closure of type (Wrapped) -> U
and transforms
Optional<Wrapped>.none --> Optional<U>.none
Optional<Wrapped>.some(wrapped) --> Optional<U>.some(transform(wrapped))
flatMap
takes a closure of type (Wrapped) -> U?
and transforms
Optional<Wrapped>.none --> Optional<U>.none
Optional<Wrapped>.some(wrapped) --> transform(wrapped)
Here transform(wrapped)
can be Optional<U>.none
as well.
If (as in your example) flatMap
is called with a closure which does not return an optional then the compiler converts it to an optional automatically, and there is no difference to map
anymore.
Swift double unwrapping of Optionals
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!
}
Unwrapping multiple Swift optionals
While Leonardo's answer is a good one, it can lead to exceptions unless you know the objects are non-optional, a better pattern is this, which should be regarded as pseudocode:
if let frame = NSScreen.screens()?.first?.frame {
// Do something with frame.
}
In other words, use optional chaining (?.
), but only use let
with the very last part of the chain.
You could also create an operator like this if you want to chain optionals that are of a different type, in which only the value of the last one will be returned:
infix operator ??? { associativity left }
func ??? <T1, T2>(t1: T1?, t2: @autoclosure () -> T2?) -> T2? {
return t1 == nil ? nil : t2()
}
if let frame = self.window ??? NSScreen.screens()?.first?.frame {
// Do something with frame
}
This is, of course, inspired by Haskell's bind. But as fun as this is, I don't recommend it. I think it's clear as mud. (By the way, the difference between ???
and ??
is that the former does not require the lhs and rhs to be of the same type (or supertype), while the latter does. ???
always returns its rhs or nil
.)
Unwrapping Swift optional without variable reassignment
No. You should unwrap your optionals just redefining it with the same name as you mentioned. This way you don't need to create a second var.
func someFunction(childTitle: String?) {
if let childTitle = childTitle {
...
}
}
update: Xcode 7.1.1 • Swift 2.1
You can also use guard as follow:
func someFunction(childTitle: String?) {
guard let childTitle = childTitle else {
return
}
// childTitle it is not nil after the guard statement
print(childTitle)
}
Optional issue converting String to Int in Swift 1.2
The first IF is always true.
Infact in both cases:
- when the
toInt()
returns a validInt
- when returns
nil
the if let
will succeed (and yes, the first IF is useless).
Specifically in your code toInt()
returns nil
in both scenarios.
But in your first scenario you are simply accepting nil
as a valid value to enter the THEN block.
Check if optional array is empty
Updated answer for Swift 3 and above:
Swift 3 has removed the ability to compare optionals with >
and <
, so some parts of the previous answer are no longer valid.
It is still possible to compare optionals with ==
, so the most straightforward way to check if an optional array contains values is:
if array?.isEmpty == false {
print("There are objects!")
}
Other ways it can be done:
if array?.count ?? 0 > 0 {
print("There are objects!")
}
if !(array?.isEmpty ?? true) {
print("There are objects!")
}
if array != nil && !array!.isEmpty {
print("There are objects!")
}
if array != nil && array!.count > 0 {
print("There are objects!")
}
if !(array ?? []).isEmpty {
print("There are objects!")
}
if (array ?? []).count > 0 {
print("There are objects!")
}
if let array = array, array.count > 0 {
print("There are objects!")
}
if let array = array, !array.isEmpty {
print("There are objects!")
}
If you want to do something when the array is nil
or is empty, you have at least 6 choices:
Option A:
if !(array?.isEmpty == false) {
print("There are no objects")
}
Option B:
if array == nil || array!.count == 0 {
print("There are no objects")
}
Option C:
if array == nil || array!.isEmpty {
print("There are no objects")
}
Option D:
if (array ?? []).isEmpty {
print("There are no objects")
}
Option E:
if array?.isEmpty ?? true {
print("There are no objects")
}
Option F:
if (array?.count ?? 0) == 0 {
print("There are no objects")
}
Option C exactly captures how you described it in English: "I want to do something special only when it is nil or empty." I would recommend that you use this since it is easy to understand. There is nothing wrong with this, especially since it will "short circuit" and skip the check for empty if the variable is nil
.
Previous answer for Swift 2.x:
You can simply do:
if array?.count > 0 {
print("There are objects")
} else {
print("No objects")
}
As @Martin points out in the comments, it uses func ><T : _Comparable>(lhs: T?, rhs: T?) -> Bool
which means that the compiler wraps 0
as an Int?
so that the comparison can be made with the left hand side which is an Int?
because of the optional chaining call.
In a similar way, you could do:
if array?.isEmpty == false {
print("There are objects")
} else {
print("No objects")
}
Note: You have to explicitly compare with false
here for this to work.
If you want to do something when the array is nil
or is empty, you have at least 7 choices:
Option A:
if !(array?.count > 0) {
print("There are no objects")
}
Option B:
if !(array?.isEmpty == false) {
print("There are no objects")
}
Option C:
if array == nil || array!.count == 0 {
print("There are no objects")
}
Option D:
if array == nil || array!.isEmpty {
print("There are no objects")
}
Option E:
if (array ?? []).isEmpty {
print("There are no objects")
}
Option F:
if array?.isEmpty ?? true {
print("There are no objects")
}
Option G:
if (array?.count ?? 0) == 0 {
print("There are no objects")
}
Option D exactly captures how you described it in English: "I want to do something special only when it is nil or empty." I would recommend that you use this since it is easy to understand. There is nothing wrong with this, especially since it will "short circuit" and skip the check for empty if the variable is nil
.
Related Topics
Table View's 'Cellforrow(At:)' Is 'Nil' in Unit Test
How to Initialize UIbezierpath to Draw a Circle in Swift
How to Byte Reverse Nsdata Output in Swift The Littleendian Way
How to Compare Two Dates (Nsdate) in Swift 3 and Get The Days Between Them
Convert Single File to Swift 3 in Xcode 8
Swift Error "Domain=Nscocoaerrordomain Code=3840 "Invalid Value Around Character 1."
Uibutton Action Is Not Triggered After Constraint Layouts Changed
Why Is Inceptionv3 Machine Learning Model Not Recognized on My Project
Xcodebuild Commands Failed to Generate Ipa
Uisearchcontroller Searchbar Misaligns While Active During Rotation
How to Condense Unwrapping Multiple Optionals in Swift