Comparing non-optional value of type 'Bool' to 'nil' always returns true - swift

I have an if-else statement where I am checking if the value coming from user defaults is nil or not like this:
if defaults.bool(forKey: "abcd") != nil{
//Do something
}
else{
//do something else
}
But Xcode is giving me an error saying:
"Comparing non-optional value of type 'Bool' to 'nil' always returns true"
Can someone explain what's happening here and how to fix this?

bool(forKey:) returns a NON-optional, which cannot be nil. If the key is missing in the user defaults, the return value will be false.
If you want trinary logic here (nil/true/false) use object(forKey:) looking for an NSNumber, and if present, take its boolValue.

As
defaults.bool(forKey: "abcd")
will return false by default check Docs , so it will never be optional
The Boolean value associated with the specified key. If the specified key doesn‘t exist, this method returns false.

The func bool(forKey: "abcd") returns Bool type not optional.
Which means you cant compare it to bool, what you can do is simply:
if defaults.bool(forKey: "abcd") {
//Do something
} else {
//do something else
}
Now if the key exists and has true value it will get into the if statement, if it does not exists or is false it will go to the else.
If you have any doubts you can read about the func in the following Apple developer link: Apple:bool(forKey:)

Objective-c property in swift. If you're using some objective c property in swift and it says something like "Comparing non-optional value of type 'XYZ' to 'nil' always returns true" you have to make that objective c property to "_Nullable" so that property may not be optional anymore. Like #property (strong,nonatomic) NSString *_Nullable someString;

defaults.bool(forKey: "abcd") != nil
The first part, defaults.bool(forKey: "abcd"), returns a non-optional boolean. We know that because bool(forKey:) returns Bool, not Bool?. Therefore, you'll always get a Bool value, i.e. either true or false, never nil. Note the documentation:
If the specified key doesn‘t exist, this method returns false.
"Comparing non-optional value of type 'Bool' to 'nil' always returns true"
The compiler is simply pointing out that it knows that defaults.bool(forKey: "abcd") can't be nil, and since you're comparing it to nil, you're probably making a mistake. Your else block will never execute.
Can someone explain what's happening here and how to fix this?
It depends on what you mean for the code to do. If you want to take different actions depending on whether the value is true or false, then compare it to one of those values. If you want to get an optional value back, use object(forKey:) (which returns an optional) instead.

i solved like this:
if(Userdefaults.standart.bool(forkey: "blablabool"){
}
This works..
When you call this if its null it returns false.

Related

how to set optional parameter in function on Swift [duplicate]

When I set firstThing to default nil this will work, without the default value of nil I get a error that there is a missing parameter when calling the function.
By typing Int? I thought it made it optional with a default value of nil, am I right? And if so, why doesn't it work without the = nil?
func test(firstThing: Int? = nil) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
test()
Optionals and default parameters are two different things.
An Optional is a variable that can be nil, that's it.
Default parameters use a default value when you omit that parameter, this default value is specified like this: func test(param: Int = 0)
If you specify a parameter that is an optional, you have to provide it, even if the value you want to pass is nil. If your function looks like this func test(param: Int?), you can't call it like this test(). Even though the parameter is optional, it doesn't have a default value.
You can also combine the two and have a parameter that takes an optional where nil is the default value, like this: func test(param: Int? = nil).
The default argument allows you to call the function without passing an argument. If you don't pass the argument, then the default argument is supplied. So using your code, this...
test()
...is exactly the same as this:
test(nil)
If you leave out the default argument like this...
func test(firstThing: Int?) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
...then you can no longer do this...
test()
If you do, you will get the "missing argument" error that you described. You must pass an argument every time, even if that argument is just nil:
test(nil) // this works
Swift is not like languages like JavaScript, where you can call a function without passing the parameters and it will still be called. So to call a function in Swift, you need to assign a value to its parameters.
Default values for parameters allow you to assign a value without specifying it when calling the function. That's why test() works when you specify a default value on test's declaration.
If you don't include that default value, you need to provide the value on the call: test(nil).
Also, and not directly related to this question, but probably worth to note, you are using the "C++" way of dealing with possibly null pointers, for dealing with possible nil optionals in Swift. The following code is safer (specially in multithreading software), and it allows you to avoid the forced unwrapping of the optional:
func test(firstThing: Int? = nil) {
if let firstThing = firstThing {
print(firstThing)
}
print("done")
}
test()
You are conflating Optional with having a default. An Optional accepts either a value or nil. Having a default permits the argument to be omitted in calling the function. An argument can have a default value with or without being of Optional type.
func someFunc(param1: String?,
param2: String = "default value",
param3: String? = "also has default value") {
print("param1 = \(param1)")
print("param2 = \(param2)")
print("param3 = \(param3)")
}
Example calls with output:
someFunc(param1: nil, param2: "specific value", param3: "also specific value")
param1 = nil
param2 = specific value
param3 = Optional("also specific value")
someFunc(param1: "has a value")
param1 = Optional("has a value")
param2 = default value
param3 = Optional("also has default value")
someFunc(param1: nil, param3: nil)
param1 = nil
param2 = default value
param3 = nil
To summarize:
Type with ? (e.g. String?) is an Optional may be nil or may contain an instance of
Type
Argument with default value may be omitted from a call to
function and the default value will be used
If both Optional and has default, then it may be omitted from function call OR may be included and can be provided with a nil value (e.g. param1: nil)
in case you need to use a bool param, you need just to assign the default value.
func test(WithFlag flag: Bool = false){.....}
then you can use without or with the param:
test() //here flag automatically has the default value: false
test(WithFlag: true) //here flag has the value: true
"Optional parameter" means "type of this parameter is optional". It does not mean "This parameter is optional and, therefore, can be ignored when you call the function".
The term "optional parameter" appears to be confusing. To clarify, it's more accurate to say "optional type parameter" instead of "optional parameter" as the word "optional" here is only meant to describe the type of parameter value and nothing else.
If you want to be able to call the func with or without the parameter you can create a second func of the same name which calls the other.
func test(firstThing: Int?) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
func test() {
test(firstThing: nil)
}
now you can call a function named test without or without the parameter.
// both work
test()
test(firstThing: 5)
Don't let the question mark fools you!
Optional is an enum which has two cases:
#frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
}
code from the original compiled source of the Optional inside Xcode
When you are defining a function that accept some Type of arguments, you can pass a default value withe the same type.
in your case
the type of the firstThing is Optional<Int> (also known as Int?). So if you want the caller to the oportunity to ignore the paramter, you MUST do the job for the caller and pass a default value.
Usually we need the .none case of the optional so we can do:
func test(firstThing: Optional<Int> = .none) { ... }
This is exactly the same as:
func test(firstThing: Int? = nil) { ... }
Also!
Who seys that we the default value of an optional is a nil? maybe passing nil means that the function should remove something by updating it's value to 'nil'. So don't asume "the default value for optional is a nil"
It is little tricky when you try to combine optional parameter and default value for that parameter. Like this,
func test(param: Int? = nil)
These two are completely opposite ideas. When you have an optional type parameter but you also provide default value to it, it is no more an optional type now since it has a default value. Even if the default is nil, swift simply removes the optional binding without checking what the default value is.
So it is always better not to use nil as default value.
Default value doesn't mean default value of data type .Here default value mean value defined at the time of defining function.
we have to declare default value of variable while defining variable in function.

"Value of optional type 'Set<String>?' must be unwrapped", but I didn't ask for an optional

Xcode complains "Value of optional type 'Set?' must be unwrapped to refer to member 'contains' of wrapped base type 'Set'"
Here's the function:
func talks_to (_ dialog_dict: Dictionary<String, Set<String>>, one: String, two: String) -> Bool {
return dialog_dict[one].contains(two)
}
This is a nested function, meant only to make logic clearer, and the parameters are guaranteed to be non-nil by the outer code. How do I get swift to understand this?
Any time you fetch an item from a dictionary using subscripting, the result is an Optional because the key you use might not be found. Sh_Khan gave you a nice elegant solution: (voted)
return dialog_dict[one]?.contains(two) == true
That works because nil does not equal true, but the compiler will unwrap it and check the value inside to see if it equals true if it's not nil. So if the result of dialog_dict[one] is nil or false, it does not equal true. Only if dialog_dict contains a value for the key one and that value is true does the expression return true.
Make it
return dialog_dict[one]?.contains(two) == true
or
return dialog_dict[one]!.contains(two)
this dialog_dict[one] returns optional

Why casting nil value as Any is not considered as nil? [duplicate]

I'm iterating through a dictionary of [String: Any], looking for nils, so I can replace them with NSNull for a JSON write. My precompiler warning is telling me that comparing an Any to a nil will always be false, but I know it contains at least two nils which are never found. Is there a way to check is an Any is nil?
An Optional can be nil. Anything else can never be nil. An Any is not an Optional. Thus there is no point comparing an Any to nil. The test will never succeed.
If you know that these things might be Optionals, you should have typed this as Any?. That is an Optional and can be compared to nil. Here's a simple example:
let s : String? = nil
let any : Any? = s
if any == nil {
print("nil") // nil
}
As you can see, the test succeeds.
(Still, if at all possible, it would be even better to type things more precisely.)
I have solved this using bellow expression:
let filteredResult = dictionary.filter { !(($0.value as AnyObject) is NSNull) }
if(object_getClass(yourVariable)?.description() == "NSNull")
can be one of the way to check.
Objective-c property in swift.
If you're using some objective c property in swift and it says something like "Comparing non-optional value of type 'XYZ' to 'nil' always returns true" you have to make that objective c property to "_Nullable" so that property may not be optional anymore. Like
#property (strong,nonatomic) NSString *_Nullable someString;

How to check for nil inside extension

Following code
extension String {
func isValidEmail() -> Bool {
if self == nil { return false }
Gives me error Value of type 'String' can never be nil, comparison isn't allowed
Is it possible to somehow check for nil here?
Checking for nil there is not required.
That function is an instance function on String.
It can only ever be run on an instance of String.
Secondly Swift does not have "nil messaging" like Objective-C so the String instance that the function is called on HAS to be not nil. Even in Objective-C this would still not matter as the function would not run if called on a nil String.
So, the message is correct, Value of type "String" can never be nil.
You could check if your string is empty as:
var myString : String?
if myString.isEmpty {
// do whatever you want ..
}
That's has more sense..
Recall that in Swift, values of type String can never be nil; if you wanted a nillable value, you'd have to declare it String?.
So no, there is no way to check if a String variable is set to nil, because it can't.

Comparing non-optional Any to nil is always false?

I'm iterating through a dictionary of [String: Any], looking for nils, so I can replace them with NSNull for a JSON write. My precompiler warning is telling me that comparing an Any to a nil will always be false, but I know it contains at least two nils which are never found. Is there a way to check is an Any is nil?
An Optional can be nil. Anything else can never be nil. An Any is not an Optional. Thus there is no point comparing an Any to nil. The test will never succeed.
If you know that these things might be Optionals, you should have typed this as Any?. That is an Optional and can be compared to nil. Here's a simple example:
let s : String? = nil
let any : Any? = s
if any == nil {
print("nil") // nil
}
As you can see, the test succeeds.
(Still, if at all possible, it would be even better to type things more precisely.)
I have solved this using bellow expression:
let filteredResult = dictionary.filter { !(($0.value as AnyObject) is NSNull) }
if(object_getClass(yourVariable)?.description() == "NSNull")
can be one of the way to check.
Objective-c property in swift.
If you're using some objective c property in swift and it says something like "Comparing non-optional value of type 'XYZ' to 'nil' always returns true" you have to make that objective c property to "_Nullable" so that property may not be optional anymore. Like
#property (strong,nonatomic) NSString *_Nullable someString;