Swift - How to check if var is nil? - ios

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");
}

Related

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 3: Cant unwrap optional from Dictionary?

Ok I don't know what is going on here. I have a dictionary of Strings below:
var animals = ["max": "z", "Royal": nil] //store key pairs
and I am unable to print the value of the value in the key value pair without it printing "Optional" along with it.
I have tried using ! !! and casting as a String as well as the following:
var animalsToReturn = [String]()
if animals[selected]! != nil
{
if let pairName = animals[selected]
{
print("\(pairName)")
print("has pair",selected, animals[selected]!)
//trying to append to another array here
animalsToReturn.append("\(animals[selected]!)")
animalsToReturn.append(selected)
}
}
else {
print("no pair")
}
I check to make sure the value isn't nil, so it won't crash if I unwrap. But this is what is printed and the word Optional is appended to my other array:
You have included nil as a value, so the type of your dictionary's value is not String but Optional<String>. But fetching a value by key from a dictionary is itself an Optional. Therefore:
If your entry is present and is ultimately a String, it is an Optional<Optional<String>> and you have to unwrap it twice.
If your entry is present and is ultimately nil, it is an Optional wrapping nil.
If your entry is not present, it is nil.
You can readily test this as follows:
func test(_ selected:String) {
var animals = ["max": "z", "Royal": nil]
if let entry = animals[selected] { // attempt to find
if let entry = entry { // attempt to double-unwrap
print("found", entry)
} else {
print("found nil")
}
} else {
print("not found")
}
}
test("max") // found z
test("Royal") // found nil
test("glop") // not found
Contemplation of that example will answer your original question, namely "I don't know what is going on here".
animals[selected] is a Optional<Optional<String>> because you're storing nil. You can:
Double unwrap your value either by using if let or ! twice.
Change the type of your dictionary to [String: String] (instead of [String: String?]), and thus avoiding nil values.
Flatten the dictionary, removing nil values, and then accessing it as a [String: String]
You can flatten the dictionary using the code in this question.
Please enclose that in bracket and use double unwrapping. try this : -
animalsToReturn.append("\((animals[selected])!!)")
func addAnimal(_ animal: String) {
guard let animal = animals[animal] else {
print("No pair")
return
}
animalsToReturn.append(animal ?? "")
}

Swift: Nil is incompatible with return type String

I have this code in Swift:
guard let user = username else{
return nil
}
But I'm getting the following errors:
Nil is incompatible with return type String
Any of you knows why or how I return nil in this case?
I'll really appreciate your help
Does your function declare an optional return type?
func foo() -> String? { ...
See more on: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
NOTE
The concept of optionals doesn’t exist in C or Objective-C. The
nearest thing in Objective-C is the ability to return nil from a
method that would otherwise return an object, with nil meaning “the
absence of a valid object.”
You have to tell the compiler that you want to return nil. How do you that? By assigning ? after your object. For instance, take a look at this code:
func newFriend(friendDictionary: [String : String]) -> Friend? {
guard let name = friendDictionary["name"], let age = friendDictionary["age"] else {
return nil
}
let address = friendDictionary["address"]
return Friend(name: name, age: age, address: address)
}
Notice how I needed to tell the compiler that my object Friend, which I'm returning, is an optional Friend?. Otherwise it will throw an error.
*Does your function declare an optional return type?
func minAndmax(array:[Int])->(min:Int, max:Int)? {
if array.isEmpty {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array {
if value < currentMin {
currentMin = value
}
else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minAndmax(array: [8, -6, 2, 109, 3, 71]) {
print(bounds)
}

How to check if NSDictionary is not nil in Swift 2

I'm getting NSDictionary as parameter in my function but having problem because don't know how to check if that parameter is not nil.
My function looks like this:
func doSmth(val : NSDictionary)
Inside my function I'm trying to get some values:
let action = val["action"] as! String
But getting error "fatal error: unexpectedly found nil while unwrapping an Optional value" when receive parameter val as nil.
The error is due to assuming (force casting) a value that can sometimes be nil. Swift is awesome, because it allows conditional unwraps and conditional casts in very concise statements. I recommend the following (for Swift 1-3):
Use "if let" to conditionally check for "action" in the dictionary.
Use as? to conditionally cast the value to a String
if let actionString = val["action"] as? String {
// action is not nil, is a String type, and is now stored in actionString
} else {
// action was either nil, or not a String type
}
You can also access the allKeys or alternatively allValues property and check if the array contains any elements like so:
let dic = NSDictionary()
let total = dic.allKeys.count
if total > 0 {
// Something's in there
}
else {
// Nothing in there
}
EDIT
Here is how you can detect if the NSDictionary is nil, if they key you are looking for exists, and if it does attempt to access it's value:
let yourKey = "yourKey"
if let dic = response.someDictionary as? NSDictionary {
// We've got a live one. NSDictionary is valid.
// Check the existence of key - OR check dic.allKeys.containsObject(yourKey).
let keyExists: Bool = false;
for var key as String in dic.allKeys {
if key == yourKey {
keyExists = true;
}
}
// If yourKey exists, access it's possible value.
if keyExists == true {
// Access your value
if let value = dic[yourKey] as? AnyObject {
// We're in business. We have the value!
}
else {
// yourKey does not contain a value.
}
}
else {
// yourKey does not exist in NSDictionary.
}
}
else {
// Call an ambulance. NSDictionary is nil.
}
That's not particularly related to Swift 2.
If the dictionary could be nil declare it as optional
func doSmth(val : NSDictionary?)
Then use optional bindings to check
if let valIsNonOptional = val {
let action = valIsNonOptional["action"] as! String
}
The code assumes that there is a key action containing a String value anyway if the dictionary is not nil
Your dictionary parameter is probably not nil. The problem is probably that your dictionary doesn't contain a value for the key "action".
When you say val["action"], the dictionary (being an NSDictionary) returns an Optional<AnyObject>. If val contains the key "action", it returns Some(value). If val doesn't contain the key "action", it returns None, which is the same as nil.
You can unwrap the Optional in your cast, and choose a course of action based on whether it was nil, using an if-let statement:
if let action = val["action"] as? String {
// action is a String, not an Optional<String>
} else {
// The dictionary doesn't contain the key "action", and
// action isn't declared in this scope.
}
If you really think val itself might be nil, you need to declare your function that way, and you can unwrap val without renaming it using a somewhat confusing guard statement:
func doSmth(val: NSDictionary?) {
guard let val = val else {
// If val vas passed in as nil, I get here.
return
}
// val is now an NSDictionary, not an Optional<NSDictionary>.
...
}

Check if optional array is empty

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’

Resources