In Objective-C, when I have an array
NSArray *array;
and I want to check if it is not empty, I always do:
if (array.count > 0) {
NSLog(@"There are objects!");
} else {
NSLog(@"There are no objects...");
}
That way, there is no need to check if array == nil
since this situation will lead the code to fall into the else
case, as well as a non-nil
but empty array would do.
However, in Swift, I have stumbled across the situation in which I have an optional array:
var array: [Int]?
and I am not being able to figure out which condition to use. I have some options, like:
Option A: Check both non-nil
and empty cases in the same condition:
if array != nil && array!.count > 0 {
println("There are objects")
} else {
println("No objects")
}
Option B: Unbind the array using let
:
if let unbindArray = array {
if (unbindArray.count > 0) {
println("There are objects!")
} else {
println("There are no objects...")
}
} else {
println("There are no objects...")
}
Option C: Using the coalescing operator that Swift provides:
if (array?.count ?? 0) > 0 {
println("There are objects")
} else {
println("No objects")
}
I do not like the option B very much, because I am repeating code in two conditions. But I am not really sure about whether options A and C are correct or I should use any other way of doing this.
I know that the use of an optional array could be avoided depending on the situation, but in some case it could be necessary to ask if it is empty. So I would like to know what is the way to do it the simplest way.
EDIT:
As @vacawama pointed out, this simple way of checking it works:
if array?.count > 0 {
println("There are objects")
} else {
println("No objects")
}
However, I was trying the case in which I want to do something special only when it is nil
or empty, and then continue regardless whether the array has elements or not. So I tried:
if array?.count == 0 {
println("There are no objects")
}
// Do something regardless whether the array has elements or not.
And also
if array?.isEmpty == true {
println("There are no objects")
}
// Do something regardless whether the array has elements or not.
But, when array is nil
, it does not fall into the if
body. And this is because, in that case, array?.count == nil
and array?.isEmpty == nil
, so the expressions array?.count == 0
and array?.isEmpty == true
both evaluate to false
.
So I am trying to figure out if there is any way of achieve this with just one condition as well.
Instead of using
if
andelse
it is better way just to useguard
to check for empty array without creating new variables for the same array.The elegant built-in solution is Optional's
map
method. This method is often forgotten, but it does exactly what you need here; it allows you to send a message to the thing wrapped inside an Optional, safely. We end up in this case with a kind of threeway switch: we can sayisEmpty
to the Optional array, and get true, false, or nil (in case the array is itself nil).Extension Property on the
Collection
Protocol*Written in Swift 3
Example Use:
Other Options
Other than the extension above, I find the following option most clear without force unwrapping optionals. I read this as unwrapping the optional array and if nil, substituting an empty array of the same type. Then, taking the (non-optional) result of that and if it
isEmpty
execute the conditional code.Recommended
Though the following reads clearly, I suggest a habit of avoiding force unwrapping optionals whenever possible. Though you are guaranteed that
array
will never benil
whenarray!.isEmpty
is executed in this specific case, it would be easy to edit it later and inadvertently introduce a crash. When you become comfortable force unwrapping optionals, you increase the chance that someone will make a change in the future that compiles but crashes at runtime.Not Recommended!
I find options that include
array?
(optional chaining) confusing such as:Confusing?
Option D: If the array doesn't need to be optional, because you only really care if it's empty or not, initialise it as an empty array instead of an optional:
Now it will always exist, and you can simply check for
isEmpty
.Conditional unwrapping:
EDIT: Possible since Swift 1.2:
EDIT: Possible since Swift 2.0:
Swift 3-4 compatible:
Usage:
Or