Check if optional array is empty - ios

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.

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.

Extension Property on the Collection Protocol
*Written in Swift 3
extension Optional where Wrapped: Collection {
var isNilOrEmpty: Bool {
switch self {
case .some(let collection):
return collection.isEmpty
case .none:
return true
}
}
}
Example Use:
if array.isNilOrEmpty {
print("The array is nil or empty")
}
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
if (array ?? []).isEmpty {
print("The array is nil or empty")
}
Though the following reads clearly, I suggest a habit of avoiding force unwrapping optionals whenever possible. Though you are guaranteed that array will never be nil when array!.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!
if array == nil || array!.isEmpty {
print("The array is nil or empty")
}
I find options that include array? (optional chaining) confusing such as:
Confusing?
if !(array?.isEmpty == false) {
print("The array is nil or empty")
}
if array?.isEmpty ?? true {
print("There are no objects")
}

Swift extension:
extension Optional where Wrapped: Collection {
var nilIfEmpty: Optional {
switch self {
case .some(let collection):
return collection.isEmpty ? nil : collection
default:
return nil
}
}
var isNilOrEmpty: Bool {
switch self {
case .some(let collection):
return collection.isEmpty
case .none:
return true
}
}
Usage:
guard let array = myObject?.array.nilIfEmpty else { return }
or:
if myObject.array.isNilOrEmpty {
// Do stuff here
}

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:
var array = [Int]()
Now it will always exist, and you can simply check for isEmpty.

Conditional unwrapping:
if let anArray = array {
if !anArray.isEmpty {
//do something
}
}
EDIT: Possible since Swift 1.2:
if let myArray = array where !myArray.isEmpty {
// do something with non empty 'myArray'
}
EDIT: Possible since Swift 2.0:
guard let myArray = array where !myArray.isEmpty else {
return
}
// do something with non empty 'myArray'

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 say isEmpty to the Optional array, and get true, false, or nil (in case the array is itself nil).
var array : [Int]?
array.map {$0.isEmpty} // nil (because `array` is nil)
array = []
array.map {$0.isEmpty} // true (wrapped in an Optional)
array?.append(1)
array.map {$0.isEmpty} // false (wrapped in an Optional)

It's better to use if to check for empty array. Why bcoz, for example if we try to find greatest integer in a list array, obviously we will compare list[0] with every integer in a list. at that time it gives us Index out of range exception.... you can try this with both IF & Guard
func findGreatestInList(list: [Int]?)-> Int? {
if list!.count == 0 {
print("List is empty")
return nil
}
/*guard list!.isEmpty else {
print("List is empty")
return nil
}*/
var greatestValue = list![0]
for number in 0...list!.count-1 {
if list![number] > greatestValue {
greatestValue = list![number]

Instead of using if and else it is better way just to use guard to check for empty array without creating new variables for the same array.
guard !array.isEmpty else {
return
}
// do something with non empty ‘array’

Related

Using an if condition for a variable? in Swift 5

I am not sure how to call this scenario. Say i have this variable
let text: String?
How can it be coded such that my if condition would be something like this:
if (text == nil || Float(text) > 0) {
print("i am in")
}
I keep getting No exact matches in call to initializer
You have two issues here:
text is a String? and therefore it needs to be unwrapped to pass it to Float()
Float() returns an optional, this also should be unwrapped to be used with the > operator.
I would avoid force unwrapping, you can do something like:
let text: String? = nil
if let textString = text, let number = Float(textString) {
if number > 0 {
print("I am in")
}
else {
print("I am out")
}
}
else {
print("I am in")
}
First of all, looks like you want to check if text != nil then if text is number check if text > 0
Because in here you have optional String so you should have a specific to check if string text not nil. Then check if it is number.
Code will be like this
extension String {
var isNumber: Bool {
return Double(self) != nil
}
}
Then combine to your condition
if text == nil || (text!.isNumber && Float(text!)! > 0) {
print("i am in")
}
The result will be like this
let text: String? = "2.0" // i am in
let text: String? = nil // i am in
let text: String? = "-1.0" // nothing print
text is an optional
if (text == nil) || Float(text ?? "") ?? 0 > 0 {
print("i am in")
}
Two additional things must be done:
After your check if text is nil you must still unwrap the optional text to use it with the Float() constructor. Here I’ve used a forced unwrap ! which in general is dangerous, but we know at this point text cannot be nil due to the first test. If text is nil, the || uses short-circuit evaluation to return true without executing the right side.
Next, Float(text!) returns a Float? because that text might not convert to a valid Float. In order to unwrap that I’ve used the nil-coalescing operator ?? to unwrap the Float value or use 0 if the value is nil.
if text == nil || Float(text!) ?? 0 > 0 {
print("i am in")
}

How to Check if 3 Variables are equal or not equal to each other in Swift 5?

i am currently working on an App that needs to compare three Variables with each other.
Rules for Comparison: The result should only be true if:
All three variables are equal OR All three variables are different
My first idea was something like this, but I hope there is a more elegant solution for this:
if (value1 == value2 && value2 == value3) || (value1 != value2 && value2 != value3 && value3 != value1) {
// True
} else {
// False
}
I would be really happy if someone of you can think of a more elegant solution and share it with me.
Thanks for your help in advance!
If your values are also Hashable you can use a Set. Given the fact that a Set discards duplicate values, you can simplify your check to something like this:
let valuesArray = [value1, value2, value3]
let valuesSet = Set(valuesArray)
if valuesSet.count == 1 || valuesSet.count == valuesArray.count {
// True
} else {
// False
}
For a one-off, that's not too bad.
The more "general" solution is kind of messy, because it needs to track 2 different boolean variables, and handle empty collections correctly.
extension Sequence where Element: Equatable {
func classifyElementEquality() -> (allEqual: Bool, allUnequal: Bool) {
var iterator = self.makeIterator()
guard let first = iterator.next() else {
return (true, true) // all empty
}
return AnyIterator(iterator)
.reduce(into: (allEqual: true, allUnequal: true)) { acc, element in
if first == element {
acc.allUnequal = false
} else {
acc.allEqual = false
}
}
}
}
let (value1, value2, value3) = (1, 2, 3)
let result = [value1, value2, value3].classifyElementEquality()
if result.allEqual || result.allUnequal {
print("They're either all equal, or all unequal")
} else {
print("Some of them are different")
}
It can get a bit simpler if this algorithm targets Collection insteaad of Sequence, because accessing the first element is easier without needing to manually manage an iterator.
extension Collection where Element: Equatable {
func classifyElementEquality() -> (allEqual: Bool, allUnequal: Bool) {
guard let first = self.first else {
return (true, true) // all empty
}
return self
.dropFirst()
.reduce(into: (allEqual: true, allUnequal: true)) { acc, element in
if first == element {
acc.allUnequal = false
} else {
acc.allEqual = false
}
}
}
}

value?.min != nil ? value!.min : nil not force unwrapping writing Optional(some number)

func myFunc(array:[Int]) -> (min: Int, max: Int)?
{
if array.isEmpty {return nil}
var minNumber = array[0]
var maxNumber = array[0]
for number in array {
if number < minNumber {
minNumber = number
}
else if number > maxNumber{
maxNumber = number
}
}
return (minNumber, maxNumber)
}
let tempArray:[Int] = [1,2,3,4,5,6,7]
let value = myFunc(array: tempArray)
print("The minima is: \(value?.min != nil ? value!.min : nil) the maxima is \(value?.max != nil ? value!.max : nil)")
In the given code I just wanted to make if for example, the code contains some value it will force unwrap but if it is not contained it will just print "nil". But in my code, if it contains number it will print Optional(some number).
value?.min != nil ? value!.min : nil
is a (conditional) expression and evaluates to some value which has a type.
The first expression value!.min has the type Int, but the second expression nil is an optional and has the type Int?. Therefore the type of the conditional expression becomes Int? and that is printed as "Optional(1)".
What you want is the string "nil", or the non-nil value as a string:
print("The minimum is: \(value?.min != nil ? "\(value!.min)" : "nil")")
(and similarly for the maximum). Now both expression in the conditional expression
value?.min != nil ? "\(value!.min)" : "nil")
are strings, and the result is a string as well. This can be abbreviated to
print("The minimum is: \(value.map {"\($0.min)"} ?? "nil")")
If you need this frequently then you can define an extension method on the optional type
extension Optional {
var descriptionOrNil: String {
switch self {
case .some(let wrapped): return "\(wrapped)"
case .none: return "nil"
}
}
}
and use it as
print("The minimum is: \((value?.min).descriptionOrNil)")
So if i don't understand the question wrong. You can do:
extension Optional where Wrapped == Int {
var valueOrEmpty: String {
guard let unwrapped = self else {
return "nil"
}
return "\(unwrapped)"
}
}
print("The minima is: \(value?.min.valueOrEmpty) the maxima is \(value?.max.valueOrEmpty)")
Right?

Swift - How to check if var is nil?

I need to check if the last element in a dataArray is nil or not, so I am running this code:
if(dataArray.last == nil){
print("dataArray.last == nil");
} else {
print("dataArray.last != nil , last = " + String(dataArray.last));
}
The weird thing is that it is printing this:
dataArray.last != nil , last = Optional(nil)
It is saying that the last element is nil despite the if condition not being met. How is this possible?
Additionally, if I print String(dataArray) this is what is returned:
[itemData,itemData , itemData , nil , nil , nil].
first and last methods of array return optional value, that contains nil or element of array. Going forward, element of array can be nil by itself. Let me show easy example:
let dataArray: [String?] = ["a", nil]
let lastElement = dataArray.last
You think that lastElement have type String?, but it have type String?? instead. When you check dataArray.last for nil, you only confirm that array is not empty. I offer you to use optional binding instead:
if let lastElement = dataArray.last, _ = lastElement{
print("dataArray.last != nil , last = " + String(dataArray.last));
}else{
print("dataArray is empty OR last element of dataArray is nil");
}
As also explained in the other answers, the last property of a
collection of Element has the type Element?, and returns nil
if the collection is empty. In your case, the element type itself is
an optional type Item?, so there are three cases possible:
The array is empty: dataArray.last is nil aka .None.
The array is not empty, and the last element is nil:
dataArray.last is .Some(nil).
The array is not empty, and the last element is not nil:
dataArray.last is .Some(.Some(element).
If you want do distinguish all three cases, you have to unwrap
twice:
let dataArray: [String?] = [ "a", "b", "c", nil ] // As an example
if let lastElement = dataArray.last {
if let lastUnwrapped = lastElement {
print("Last element is", lastUnwrapped)
} else {
print("Last element is nil")
}
} else {
print("Array is empty")
}
This can be shorted with a switch and the optional pattern:
switch dataArray.last {
case let element??:
print("Last element is", element)
case let element?:
print("Last element is nil")
case nil:
print("Array is empty")
}
If you are only interested if the last element of the array is not nil,
then you can use if case with an optional pattern:
if case let element?? = dataArray.last {
print("Last element is", element)
} else {
print("Last element is nil, or array is empty")
}
Here element?? is a shortcut for .Some(.Some(element)) which
matches case #3.
If you want to re-implement the last method for arrays then it
would simply be
extension Array {
func lastMe() -> Element? {
if isEmpty {
return nil
} else {
return self[count - 1]
}
}
}
If the element type is an optional Item?, then the return type
becomes Item??.
Why are you getting that result?
Let's look at this code
let dataArray: [Int?] = [1, nil]
if let last = dataArray.last {
print(last)
}
It does print
nil
It does happen because dataArray is defined as an array of optional Int (aka Int?). So the last property does return a value that is an Optional containing nil.
So the if clause is satisfied and the body of the if is executed.
This is the correct syntax
let dataArray: [Int?] = [1, nil ,3]
if let lastOptional = dataArray.last, last = lastOptional {
print("dataArray.last != nil, last = \(last)")
} else {
print("dataArray.last == nil")
}
Output:
dataArray.last != nil, last = 3
Explanation
Let's look at the if. It is made of 2 clauses and both must be satisfied for the if to be resolved as true.
The #1 clause
let lastOptional = dataArray.last
does succeed if the last element does exist. It will be an Int? so an optional value containing nil or an Int. In both case this clause is satisfied.
Basically the first clause is satisfied when the array is NOT empty.
The #2 clause
last = lastOptional
does succeed if the optional last (Int?) element is successfully unwrapped.
This clause is satisfied when the last element does exists and is not an Optional containing nil.
Wrap-up
Inside the body of the if you can use last and you can be sure that it will be the unwrapped value. Infact the type of last is Int.
Try this
if let lastObject = dataArray.last{
print("dataArray.last != nil", + String(lastObject));
}else{
print("dataArray.last == nil );
}
Array have optional function
last
Optional(nil) is not equal to nil
if you print out dataArray.last then Optional(nil) will be printed
try this
if let _ = dataArray.last {
print("dataArray.last != nil , last = " + String(dataArray.last));
}else{
print("dataArray.last == nil");
}

Check if TWO objects are nil in Swift, ios xcode

I want to compare two objects(of the same Class) and return what is NOT nil.
How do you write something like this in swift? :
func returnWhatIsNotNil(objA: SomeClass, objB: SomeClass) -> SomeClass {
if objA != nil && objB != nil { //error
//both are not nil
return nil
}
if objA == nil && objB != nil { // error
// objA is nil
return objB
}
if objA != nil && objB == nil { // error
// objB is nil
return objA
}
}
with one object,
if let x = objA {
//objA is not nil
}
would do the job, but I quiet don't know how I would do this with TWO objects.
class SomeObject {
}
func returnWhatIsNotNil(objA: SomeObject?, objB: SomeObject?) -> SomeObject? {
if let objA = objA where objB == nil {
return objA
}
if let objB = objB where objA == nil {
return objB
}
return nil
}
edit: sorry, misread your original question. if you want nil when both are non-nil, then here is a one-liner that does it: return objA.map { objB == nil ? $0 : nil } ?? objB. However, #LeoDabus’s version using if…let…where looks more readable to me.
pre-edit assuming you want the first when neither are nil:
You want to use the nil-coalescing operator, ??. So to return an optional from your function, you just need return objA ?? objB. Note, all your input and output types also have to be optional.
Ordinarily you use it to give a default value in case of nil, i.e. "foo".toInt() ?? 0 which unwraps the value if non-nil, or replaces it with the default if its nil.
But if the right-hand side is also an optional, it will return an optional, with the left one if it’s non-nil, else the right one, even if that one is nil.
let i: Int? = nil
let j: Int? = nil
let k: Int? = 42
if let num = i ?? j {
fatalError("won't execute")
}
if let num = j ?? k {
assert(num == 42, "k will be chosen")
}
else {
fatalError("this would run if all 3 were nil")
}
Also bear in mind you can chain ?? too:
let x = i ?? j ?? k ?? 0 // will result in an unwrapped 42
As a follow up to #LeoDabus' accepted answer, you can use a switch statement also:
class SomeObject {
}
func returnWhatIsNotNil(objA: SomeObject?, objB: SomeObject?) -> SomeObject? {
switch (objA, objB) {
case (let a, nil): return a
case (nil, let b): return b
default: return nil
}
}
As mentioned the nil coalescing operator ?? can be used.
Here is an implementation of your function, note you didn't define what would happen when both objA and objB were non-nil
func returnWhatIsNotNil(objA: SomeClass?, objB: SomeClass?) -> SomeClass? {
return objA ?? objB
}
Although, a literal translation of your code in Swift is possible, which is
func returnNotNil(num1: Int?, num2: Int?) -> Int?
{
if let x = num1 {
return x
}
else if let y = num2
{
return y
}
else
{
return nil
}
}
The problem here is, in Swift, we will have to keep the return type as optional - so once returned from the function, you will again have to check for returned value being not nil, and unwrap.
IMHO, a logical translation would be, (assuming that you don't mind returning either, when none of them are nil)
func returnNotNilOrAssert(num1: Int?, num2: Int?) -> Int
{
if let x = num1 {
return x
}
else if let y = num2
{
return y
}
else
{
assert(false, "Both nil")
}
}
Whether or not to assert, is probably an implementation choice that you would have to make. Another way would be, if you're absolutely sure, that one of them would be not nil, that you make the return type of the function "implicitly unwrapped". I know you wanna return nil when both are nil, but then having to check the returned value of this function which is supposed to check two values and return the one which is not nil, IMHO wasn't making much sense, thus I tried it this way.

Resources