Best way to check a nil object - ios

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
}

Related

Multiple value checking with swifts guard statement?

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.

why I have to unwrap value before I use

A block is defined like below
// Declare block ( optional )
typealias sorting = (([Schedule], [String]) -> [Schedule])?
var sortSchedule: sorting = { (schedules, sortDescription) in
var array = [Schedule]()
for string in sortDescription
{
for (index, schedule) in schedules.enumerate()
{
if string == schedule.startTime
{
array.append(schedule)
break
}
}
}
return array
}
At some points, I am invoking a block by doing
let allSchedules = sortSchedule?(result, sortDescription())
for schedule in allSchedules // Xcode complains at here
{
..........
}
Im using ? because I want to make sure that if the block exists, then do something. However, Xcode complains for the for loop
value of optional type [Schedule]? not upwrapped, did you mean to use '!' or '?'?
Im not sure why because the return type of a block is an array which can have 0 or more than one items.
Does anyone know why xcode is complaining.
You are use ? in line let allSchedules = sortSchedule?(result, sortDescription()) not "for sure that if the block exists", but just for note, that you understand that it can be nil. Behind scene allSchedules have type Array<Schedule>?. And you can not use for in cycle for nil. You better use optional binding:
if let allSchedules = sortSchedule?(result, sortDescription())
{
for schedule in allSchedules
{
//..........
}
}

Using Swift, how can I tell the difference between a boolean and integer value when loading data from a plist?

My app needs to be able to read a plist file and know the type of data, so I created a function to figure the type of an object:
func getTypeOfObject(object: AnyObject) -> String {
if object as? [String:AnyObject] != nil {
return "dict"
} else if object as? [AnyObject] != nil {
return "array"
} else if object as? Bool != nil {
return "bool"
} else if object as? Int != nil {
return "int"
} else if object as? String != nil {
return "string"
} else {
return ""
}
}
The problem is that if I call the function on a number I get "bool" returned.
If I change the function to check for a number first I get "int" returned when I pass a boolean.
This seems to be because when I create a dict from data in the plist file booleans are given an integer value (1 for true and 0 for false).
Is there any way I can get around this?
You can't - unless you want to parse the plist XML yourself. The value returned will be NSNumber and it's up to you to decide if you want to treat it as a bool (via NSNumber's boolValue).
I did some more research and decided to use CFPropertyList, which solves my problem as booleans are CFBooleanRefs, not NSNumbers.
If anyone wants the actual code ask in the comments. It's a bit messy right now which is why I am not posting it right away.

Use of unresolved identifier in Swift

I am trying to create an if statement or a switch statement and created a variable to be used.
if (randomIcon == 1) {
var coolCircle = TapCircleIcon(typeOfCircle: CircleType.Circle1)
}
addChild(coolCircle)
The issue I get is unresolved identifier for coolCircle. This is kind of expected, but I am not sure what the swift equvilant would be.
In Obj-C I would probably set the pointer to nil, then create it if the value exists. How would I get this to parse correctly in Swift. What should I do to set the variable to TapCircleIcon class, but not create an object until the if/switch statement?
Simpler:
if (randomIcon == 1) {
let coolCircle = TapCircleIcon(typeOfCircle: CircleType.Circle1)
addChild(coolCircle)
}
More flexible:
let coolCircle: TapCircleIcon?
if (randomIcon == 1) {
coolCircle = TapCircleIcon(typeOfCircle: CircleType.Circle1)
}
else {
coolCircle = nil // or something else
}
if let coolCircle = coolCircle { // not nil
addChild(coolCircle)
}
Since the other answers don't explain anything:
You declare the variable coolCircle inside the if block which makes it available to that if block only. That means you will not be able to use it outside again.
I would go with what #fluidsonic's answer to fix the problem.
Hope that helps your understanding :)

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