Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nil checks not always working for Any in Swift

Tags:

swift

I'm confused about how Swift checks for nil when I'm using the Any type.
Here's an example:

let testA: Any? = nil
let testB: Any = testA as Any
let testC: Any? = testB

if testA != nil {
    print(testA) // is not called as expected
}
if testB != nil {
    print(testB) // prints "nil"
}
if testC != nil {
    print(testC) // prints "Optional(nil)"
}

testA works as expected. The variable is nil, so the condition is false.

testB works not as expecte. The variable is nil, as shown by the print call. But the condition testB != nil evaluates to true. Why is this the case?

testC confuses me as well, since it is testC = testB = testA. So why should it behave differently than testA?

How would I need to write the if conditions if testB ... and if testC ... to not be true.
I'm looking for a solution that doesn't require me to know the type, like ...

if let testB = testB as String

Edit: I'm testing this with Swift 4 in an Xcode 9.1 Playground file.

Edit2:
Some information about the actual problem I want to solve. I'm getting a dictionary of type [String: Any?] that is created by a JSON parser. I want to check if the value for a given key is nil, but it doesn't work, when the key exists and the value is Optional(nil).

Example:

var dict = [String: Any?]()
var string = "test"
var optionalString: String?
dict["key1"] = string
dict["key2"] = optionalString

if dict["key2"] != nil {
    print(dict["key2"]) // should not be executed, but returns Optional(nil)
}
like image 834
florieger Avatar asked Jan 06 '18 14:01

florieger


People also ask

Can any be nil Swift?

From the Swift Docs: " Any : The protocol to which all types implicitly conform." And enums are Types, so they conform to the Any protocol. As stated in the comments, nil is not a type (and thus does not conform to Any , it is the absence of a value (and in this case no value has no type).

How do you check nil in Swift?

In Swift, you can also use nil-coalescing operator to check whether a optional contains a value or not. It is defined as (a ?? b) . It unwraps an optional a and returns it if it contains a value, or returns a default value b if a is nil.

How do you check if an int variable is null or empty in Swift?

You can use if let. if let is a special structure in Swift that allows you to check if an Optional holds a value, and in case it does – do something with the unwrapped value. But for Strings you can also use . isEmpty() If you have initialized it to "" .

What is a nil value in Swift?

In Swift, nil means the absence of a value. Sending a message to nil results in a fatal error. An optional encapsulates this concept. An optional either has a value or it doesn't. Optionals add safety to the language.


1 Answers

In Swift, nil is actually a concrete value(of type enum). testB which is of Any type, is holding the enum Optional with value none and hence the condition testB != nil is true.

enter image description here

This solves the mystery of how Any of testB is able to hold the nil value.

Coming to your actual problem, I tried this piece of code in Storyboard(Xcode 9.2) and it worked as expected.

var dict = [String: Any]()
var string = "test"
var optionalString: String?
dict["key1"] = string
dict["key2"] = optionalString

if let value = dict["key2"] {
    print(value) // doesn't get executed
}

For testB and testC, it seems like == check with nil should provide a solution but, because binary operand can not be used with two Any? operands, we can not use ==.

Using switch-case though is able to give correct results:

switch testB {
case Optional<Any>.none:
    print("value is none")
default:
    print("value is not none")
}

switch testC! {
case Optional<Any>.none:
    print("value is none")
default:
    print("value is not none")
}

O/P:
value is none
value is none

like image 87
Puneet Sharma Avatar answered Oct 01 '22 19:10

Puneet Sharma