Checking if `if let` is nil - ios

I have an app where I'm currently using the SwiftKeychainWrapper. Below is the code I have which checks if retrievedString is nil. However I'm still getting retrievedString: nil in the console.
Shouldn't the code in the if-let statement not run, or am I using/understanding if-let incorrectly?
With the given example, what's the correct way to use if-let to unwrap my optional value?
if let retrievedString: String? = KeychainWrapper.stringForKey("username") {
print("retrievedString: \(retrievedString)")
//value not nil
} else {
//Value is nil
}

This is because you are setting the value of a optional String, String? KeychainWrapper.stringForKey("username") to another optional String retrievedString.
By trying to set a String? to another String?, the if let check always succeeds, even when the value is nil, because both the types are the same, and both can accept a nil value.
Instead, you should attempt to set the optional string, String? to a non-optional string, String. When Swift tries to set a non-optional String to nil, it will fail, because a non-optional cannot have a nil value. The code will then continue in the else statement
You should use
//notice the removal of the question mark
// |
// v
if let retrievedString: String = KeychainWrapper.stringForKey("username") {
print("retrievedString: \(retrievedString)")
//value not nil
} else {
//value is nil
}

You are setting the type of retrievedString to be optional. The whole point of the check is to remove the optional and just have a String.
if let retrievedString: String = KeychainWrapper.stringForKey("username") {
print("retrievedString: \(retrievedString)")
//value not nil
} else {
//Value is nil
}

Related

How force unwrapping works in function parameters in Swift? [duplicate]

This question already has answers here:
In Swift, what does the ! symbol mean in a function signature?
(2 answers)
Closed 3 years ago.
I have one function in Swift like,
func getValue(param: String!) -> String {
//access param
//return a string
}
call is like,
let retVal = getValue(param: nil)
I expected that the param will try to force unwrap while taking into the function parameters and get crashed. But the code did not crash. Can anyone let me know what am I missing?
What will be different in case of the signature,
func getValue(param: String?) -> String
Here ! means the param will hold String value or nil. So when you assign nil to ! it is not supposed to crash.
But when you try to access that value, it will crash.
This modification in your code will cause a crash as we are trying to access the value inside the variable which is nil.
func getValue(param: String!) -> String {
if param.isEmpty {
return ""
}
return ""
}
let retVal = getValue(param: nil)
Another example:
var string: String!
string = nil //This will not crash, but after this line if you try to access or perform any operation on it, it will
Now about thisfunc getValue(param: String?) :
In this scenario the the param will be optional type unlike in the above scenario. So here you will have to unwrap it.
Implicitly unwrapped optional (or IUO) may still contain nil as a value! In case of IUO you will get a crash only when you call any method/variable on it (e.g. param.count) OR when you assign it to a NON-Optional variable which will led to force unwrapping operation:
var param: String! = nil
var nonOptionalStr: String = param //<- Crash because it will try to force-unwrap param
Another example of a crash:
func foo(param: String!) -> String {
return param //<- Crash! As return type is non-optional String it will try to force unwrap the param.
}
On the other hand IUOs (as well as Optionals) are also of type Any so if you pass a String! containing nil to a method which expects Any it will not crash because there will be no force-unwrapping operation as Any? can be easily cast to Any .
let str: String! = nil
print(str) //<- No Crash! Becaise print accepts Any, so there will be no force-unwrapping
//Output: nil
Another example with type Any:
var a: Any? = nil
var b: Any = a //<- No Crash! As (Any?) is kind of (Any), though you will get a warning from compiler: Expression implicitly coerced from 'Any?' to 'Any'
print(b)
//Output: nil

I am getting a warning comparing my OPTIONAL value to not-nil will always return true

I have declared a type called "JournalEntry" as an optional and have it set to nil. Then when the VC loads I test to make sure that the object has been injected before trying to use it, but I get an error that says "Comparing non-optional value of type 'JournalEntry' to nil always returns true".
But I have it set as an optional and to nil...
Here's the code:
class AddJournalEntryVC: UIViewController, UITextViewDelegate {
var willEdit:Bool?
var entryForEdit:JournalEntry? = nil
override func viewDidLoad() {
super.viewDidLoad()
if isEditing {
guard let entry = entryForEdit, entry != nil else{ //Comparing non-optional value of type 'JournalEntry' to nil always returns true
return
}
dateLabel.text = entry.dateString!
timeLabel.text = entry.timeString!
timestamp = entry.timestamp!
}
}
Where has my thinking gone wrong? Thank you.
Just remove the entry != nil clause and it will work as you require. The if let statement that proceeds it performs the not-nil check already.
guard let entry = entryForEdit else {
return
}

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

Why doesn't guard create unwrapped var?

Why do I need to unwrap the variable unwrapped in the final return statement? Isn't guard supposed to handle this?
func test() -> String {
let fmt = NSNumberFormatter()
let myValue:Double? = 9.50
guard let unwrapped = myValue else {
return ""
}
return fmt.stringFromNumber(unwrapped)
}
error: value of optional type 'String?' not unwrapped; did you mean to
use '!' or '?'?
return fmt.stringFromNumber(unwrapped)
It's not the variable unwrapped. It's stringFromNumber: it returns an optional string. But your function returns a string, hence you must unwrap:
return fmt.stringFromNumber(unwrapped)!
There's a difference between these 2:
return fmt.stringFromNumber(unwrapped!)
return fmt.stringFromNumber(unwrapped)!

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>.
...
}

Resources