Multiple value checking with swifts guard statement? - ios

Most of my searching here on SO is proving futile. My guard statement works as far as checking each value and correcting it if one is nil. However if two of the values are nil, then I crash unexpectedly finding nil while unwrapping an optional. How does one go about checking that multiple values are not nil using swifts guard statement?
func protectInput() {
guard Double(myAmount.text!) != nil else {
myAmount.text = "0.00"
return
}
guard Double(myRate.text!) != nil else {
myRate.text = "0.00"
return
}
guard Double(myFee.text!) != nil else {
myFee.text = "0.00"
return
}
}
Maybe I am completely on the wrong track, any help with an example would be appreciated. I have read all I can take in. I do not need to compare two values or have some complex comparison.

Guard statements aren't the right thing to use here. If any of them fail, then you will return from the function and your later statements won't get executed. So if myAmount doesn't have a valid value in it, you'll never correct myRate and myFee.
if Double(myAmount.text ?? "") == nil {
myAmount.text = "0.00"
}
This pattern would suit you better:
the text value isn't force unwrapped any more, which will prevent one potential crash - ?? is the nil coalescing operator which will use either the text value or, in this case, an empty string
there is no return so the function will check all of the values.

Related

value of type 'Int' can never be nil, comparison isn't allowed in swift 2.2

if(Int(textfield.text!)! != nil) { //value of type 'Int' can never be nil, comparison isn't allowed.
//Rest of the code
}
Everything was working fine but yesterday I have updated my Xcode after that I'm getting this error. Please help.
To check for nil just remove the trailing exclamation mark to keep the result of the Int initializer as optional.
if Int(textfield.text!) != nil {
//Rest of the code
}
You're forcefully unwrapping the Int:
Int(textField.text!)! // This trailing exclamation (bang) is saying, trust me, this is not a nil
Then you're attempting to see if its nil or not with != nil
I suggest that you do a proper unwrap of the optionals like so:
if let textInt = textField.text, integerUnwrapped = Int(textInt) {
// Rest of the code
} else {
// Handle if either the text or integer is actually nil
}
If for whatever reason textField.text gets a string of characters, this code will fail inside the else statement.
The way you're handling the forceful optional unwrap however will result in a crash.

Determine "nil" value in JSON

The app receives JSON object from the server. And some field in the object can be missing, or be nil. So, I need to find them before computing a value. I have a code fragment as below:
print(package["store"]!["cover"]) //here, console output: "nil"
if ((package["store"]!["cover"]) != nil) {
//the 'if' statment above has no effect, statment below is executed,
// and error occurs.
imageName = STATIC_IMAGE_URL + (package["cover"] as! String)
}
How can I detect if the response JSON has some missing or nil fields?
You can use optional chaining, optional binding, and conditional casting combined in the same if-let statement:
if let cover = package["store"]?["cover"] as? String {
imageName = STATIC_IMAGE_URL + cover
} else {
imageName = "someDefaultImage"
}
It works like this:
package["store"]?["cover"] will return nil if either package["store"], or package["store"]["cover"] is nil
the conditional cast as? String returns nil if the expression to the left is not a String
finally the if-let construct will either populate cover with the actual string, or will go on the else branch if there's no match

replacing nil value with other customized value

I am using a keychain wrapper written in Swift.
When value is nil, this wrapper I'm using automatically saves data as "nil" instead of saving as an actual nil value.
For ex, ["last_name" : "nil"].
In one of my label in my iOS app, I'm returning last_name value.
It bothers me that a text in label is saying "nil" when there supposed to be nothing.
I remember in Swift that there is a syntax like A ?? B which puts B instead if A is not valid. But I cannot remember it right now.
In my app, I want to something like below:
if the value I'm looking for is nil, then input "" instead of "nil"
If keychain["last_name"] == nil ?? ""
I know this is a horrible explanation but this is all I could come up with.
?? is the nil coalescing operator. It is used for unwrapping optionals — a ?? b is shorthand for a != nil ? a! : b.
You probably want to use the ternary operator instead. You could even combine them like this:
let lastName = keychain["last_name"] == "nil" ? "" : (keychain["last_name"] ?? "")
That said, it might be easier to just filter out these responses immediately after getting the keychain instead of checking every time:
var keychain = ["first_name" : "aaron", "last_name" : "nil"]
keychain.forEach { if $0.1 == "nil" { keychain.removeValueForKey($0.0) } }
print(keychain) //["first_name": "aaron"]
The $0 is a shorthand argument name. Here's the long form version of the same code:
keychain.forEach { (key, value) -> () in
if value == "nil" {
keychain.removeValueForKey(key)
}
}

Best way to check a nil object

I am checking for nil object like this:
if let _ = object {
// Nothing to do here.
} else {
// There's something that must be done here.
}
I would like to remove the part let _ = object because there's nothing to execute inside it. Aside from using if object == nil, what is the best way using the optional checking to verify if a certain object is nil?
If your only intention is to check if the object is nil,
and the unwrapped value is never needed, then
a simple comparison with nil is the simplest way:
if object == nil {
print("Warning: object is nil")
}
If you want to emphasize that this check is a precondition and you want to leave the
current scope if the condition is not satisfied, then you can use
a guard statement. But there is no need to unwrap the object to the unused variable:
guard object != nil else {
print("Warning: object is nil")
return
}
You can use guard statement for this purpose
guard let _ = object else {
// Do something
return
}

Swift: Testing optionals for nil

I'm using Xcode 6 Beta 4. I have this weird situation where I cannot figure out how to appropriately test for optionals.
If I have an optional xyz, is the correct way to test:
if (xyz) // Do something
or
if (xyz != nil) // Do something
The documents say to do it the first way, but I've found that sometimes, the second way is required, and doesn't generate a compiler error, but other times, the second way generates a compiler error.
My specific example is using the GData XML parser bridged to swift:
let xml = GDataXMLDocument(
XMLString: responseBody,
options: 0,
error: &xmlError);
if (xmlError != nil)
Here, if I just did:
if xmlError
it would always return true. However, if I do:
if (xmlError != nil)
then it works (as how it works in Objective-C).
Is there something with the GData XML and the way it treats optionals that I am missing?
In Xcode Beta 5, they no longer let you do:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
This produces an error:
does not conform to protocol 'BooleanType.Protocol'
You have to use one of these forms:
if xyz != nil {
// Do something using `xyz`.
}
if let xy = xyz {
// Do something using `xy`.
}
To add to the other answers, instead of assigning to a differently named variable inside of an if condition:
var a: Int? = 5
if let b = a {
// do something
}
you can reuse the same variable name like this:
var a: Int? = 5
if let a = a {
// do something
}
This might help you avoid running out of creative variable names...
This takes advantage of variable shadowing that is supported in Swift.
Swift 3.0, 4.0
There are mainly two ways of checking optional for nil. Here are examples with comparison between them
1. if let
if let is the most basic way to check optional for nil. Other conditions can be appended to this nil check, separated by comma. The variable must not be nil to move for the next condition. If only nil check is required, remove extra conditions in the following code.
Other than that, if x is not nil, the if closure will be executed and x_val will be available inside. Otherwise the else closure is triggered.
if let x_val = x, x_val > 5 {
//x_val available on this scope
} else {
}
2. guard let
guard let can do similar things. It's main purpose is to make it logically more reasonable. It's like saying Make sure the variable is not nil, otherwise stop the function. guard let can also do extra condition checking as if let.
The differences are that the unwrapped value will be available on same scope as guard let, as shown in the comment below. This also leads to the point that in else closure, the program has to exit the current scope, by return, break, etc.
guard let x_val = x, x_val > 5 else {
return
}
//x_val available on this scope
One of the most direct ways to use optionals is the following:
Assuming xyz is of optional type, like Int? for example.
if let possXYZ = xyz {
// do something with possXYZ (the unwrapped value of xyz)
} else {
// do something now that we know xyz is .None
}
This way you can both test if xyz contains a value and if so, immediately work with that value.
With regards to your compiler error, the type UInt8 is not optional (note no '?') and therefore cannot be converted to nil. Make sure the variable you're working with is an optional before you treat it like one.
From swift programming guide
If Statements and Forced Unwrapping
You can use an if statement to find out whether an optional contains a
value. If an optional does have a value, it evaluates to true; if it
has no value at all, it evaluates to false.
So the best way to do this is
// swift > 3
if xyz != nil {}
and if you are using the xyz in if statement.Than you can unwrap xyz in if statement in constant variable .So you do not need to unwrap every place in if statement where xyz is used.
if let yourConstant = xyz {
//use youtConstant you do not need to unwrap `xyz`
}
This convention is suggested by apple and it will be followed by devlopers.
Although you must still either explicitly compare an optional with nil or use optional binding to additionally extract its value (i.e. optionals are not implicitly converted into Boolean values), it's worth noting that Swift 2 has added the guard statement to help avoid the pyramid of doom when working with multiple optional values.
In other words, your options now include explicitly checking for nil:
if xyz != nil {
// Do something with xyz
}
Optional binding:
if let xyz = xyz {
// Do something with xyz
// (Note that we can reuse the same variable name)
}
And guard statements:
guard let xyz = xyz else {
// Handle failure and then exit this code block
// e.g. by calling return, break, continue, or throw
return
}
// Do something with xyz, which is now guaranteed to be non-nil
Note how ordinary optional binding can lead to greater indentation when there is more than one optional value:
if let abc = abc {
if let xyz = xyz {
// Do something with abc and xyz
}
}
You can avoid this nesting with guard statements:
guard let abc = abc else {
// Handle failure and then exit this code block
return
}
guard let xyz = xyz else {
// Handle failure and then exit this code block
return
}
// Do something with abc and xyz
Swift 5 Protocol Extension
Here is an approach using protocol extension so that you can easily inline an optional nil check:
import Foundation
public extension Optional {
var isNil: Bool {
guard case Optional.none = self else {
return false
}
return true
}
var isSome: Bool {
return !self.isNil
}
}
Usage
var myValue: String?
if myValue.isNil {
// do something
}
if myValue.isSome {
// do something
}
One option that hasn't specifically been covered is using Swift's ignored value syntax:
if let _ = xyz {
// something that should only happen if xyz is not nil
}
I like this since checking for nil feels out of place in a modern language like Swift. I think the reason it feels out of place is that nil is basically a sentinel value. We've done away with sentinels pretty much everywhere else in modern programming so nil feels like it should go too.
Instead of if, ternary operator might come handy when you want to get a value based on whether something is nil:
func f(x: String?) -> String {
return x == nil ? "empty" : "non-empty"
}
Another approach besides using if or guard statements to do the optional binding is to extend Optional with:
extension Optional {
func ifValue(_ valueHandler: (Wrapped) -> Void) {
switch self {
case .some(let wrapped): valueHandler(wrapped)
default: break
}
}
}
ifValue receives a closure and calls it with the value as an argument when the optional is not nil. It is used this way:
var helloString: String? = "Hello, World!"
helloString.ifValue {
print($0) // prints "Hello, World!"
}
helloString = nil
helloString.ifValue {
print($0) // This code never runs
}
You should probably use an if or guard however as those are the most conventional (thus familiar) approaches used by Swift programmers.
Optional
Also you can use Nil-Coalescing Operator
The nil-coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
let value = optionalValue ?? defaultValue
If optionalValue is nil, it automatically assigns value to defaultValue
Now you can do in swift the following thing which allows you to regain a little bit of the objective-c if nil else
if textfieldDate.text?.isEmpty ?? true {
}
var xyz : NSDictionary?
// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary()
// case 3: do nothing
if xyz { NSLog("xyz is not nil.") }
else { NSLog("xyz is nil.") }
This test worked as expected in all cases.
BTW, you do not need the brackets ().
If you have conditional and would like to unwrap and compare, how about taking advantage of the short-circuit evaluation of compound boolean expression as in
if xyz != nil && xyz! == "some non-nil value" {
}
Granted, this is not as readable as some of the other suggested posts, but gets the job done and somewhat succinct than the other suggested solutions.
If someone is also try to find to work with dictionaries and try to work with Optional(nil).
let example : [Int:Double?] = [2: 0.5]
let test = example[0]
You will end up with the type Double??.
To continue on your code, just use coalescing to get around it.
let example : [Int:Double?] = [2: 0.5]
let test = example[0] ?? nil
Now you just have Double?
This is totally logical, but I searched the wrong thing, maybe it helps someone else.
Since Swift 5.7:
if let xyz {
// Do something using `xyz` (`xyz` is not optional here)
} else {
// `xyz` was nil
}

Resources