When should I compare an optional value to nil? - ios

Quite often, you need to write code such as the following:
if someOptional != nil {
// do something with the unwrapped someOptional e.g.
someFunction(someOptional!)
}
This seems a bit verbose, and also I hear that using the ! force unwrap operator can be unsafe and best avoided. Is there a better way to handle this?

It is almost always unnecessary to check if an optional is not nil. Pretty much the only time you need to do this is if its nil-ness is the only thing you want to know about – you don’t care what’s in the value, just that it’s not nil.
Under most other circumstances, there is a bit of Swift shorthand that can more safely and concisely do the task inside the if for you.
Using the value if it isn’t nil
Instead of:
let s = "1"
let i = Int(s)
if i != nil {
print(i! + 1)
}
you can use if let:
if let i = Int(s) {
print(i + 1)
}
You can also use var:
if var i = Int(s) {
print(++i) // prints 2
}
but note that i will be a local copy - any changes to i will not affect the value inside the original optional.
You can unwrap multiple optionals within a single if let, and later ones can depend on earlier ones:
if let url = NSURL(string: urlString),
data = NSData(contentsOfURL: url),
image = UIImage(data: data)
{
let view = UIImageView(image: image)
// etc.
}
You can also add where clauses to the unwrapped values:
if let url = NSURL(string: urlString) where url.pathExtension == "png",
let data = NSData(contentsOfURL: url), image = UIImage(data: data)
{ etc. }
Replacing nil with a default
Instead of:
let j: Int
if i != nil {
j = i
}
else {
j = 0
}
or:
let j = i != nil ? i! : 0
you can use the nil-coalescing operator, ??:
// j will be the unwrapped value of i,
// or 0 if i is nil
let j = i ?? 0
Equating an optional with a non-optional
Instead of:
if i != nil && i! == 2 {
print("i is two and not nil")
}
you can check if optionals are equal to non-optional values:
if i == 2 {
print("i is two and not nil")
}
This also works with comparisons:
if i < 5 { }
nil is always equal to other nils, and is less than any non-nil value.
Be careful! There can be gotchas here:
let a: Any = "hello"
let b: Any = "goodbye"
if (a as? Double) == (b as? Double) {
print("these will be equal because both nil...")
}
Calling a method (or reading a property) on an optional
Instead of:
let j: Int
if i != nil {
j = i.successor()
}
else {
// no reasonable action to take at this point
fatalError("no idea what to do now...")
}
you can use optional chaining, ?.:
let j = i?.successor()
Note, j will also now be optional, to account for the fatalError scenario. Later, you can use one of the other techniques in this answer to handle j’s optionality, but you can often defer actually unwrapping your optionals until much later, or sometimes not at all.
As the name implies, you can chain them, so you can write:
let j = s.toInt()?.successor()?.successor()
Optional chaining also works with subscripts:
let dictOfArrays: ["nine": [0,1,2,3,4,5,6,7]]
let sevenOfNine = dictOfArrays["nine"]?[7] // returns {Some 7}
and functions:
let dictOfFuncs: [String:(Int,Int)->Int] = [
"add":(+),
"subtract":(-)
]
dictOfFuncs["add"]?(1,1) // returns {Some 2}
Assigning to a property on an optional
Instead of:
if splitViewController != nil {
splitViewController!.delegate = self
}
you can assign through an optional chain:
splitViewController?.delegate = self
Only if splitViewController is non-nil will the assignment happen.
Using the value if it isn’t nil, or bailing (new in Swift 2.0)
Sometimes in a function, there’s a short bit of code you want to write to check an optional, and if it’s nil, exit the function early, otherwise keep going.
You might write this like this:
func f(s: String) {
let i = Int(s)
if i == nil { fatalError("Input must be a number") }
print(i! + 1)
}
or to avoid the force unwrap, like this:
func f(s: String) {
if let i = Int(s) {
print(i! + 1)
}
else {
fatalErrr("Input must be a number")
}
}
but it’s much nicer to keep the error-handling code at the top by the check. This can also lead to unpleasant nesting (the "pyramid of doom").
Instead you can use guard, which is like an if not let:
func f(s: String) {
guard let i = Int(s)
else { fatalError("Input must be a number") }
// i will be an non-optional Int
print(i+1)
}
The else part must exit the scope of the guarded value, e.g. a return or fatalError, to guarantee that the guarded value will be valid for the remainder of the scope.
guard isn’t limited to function scope. For example the following:
var a = ["0","1","foo","2"]
while !a.isEmpty {
guard let i = Int(a.removeLast())
else { continue }
print(i+1, appendNewline: false)
}
prints 321.
Looping over non-nil items in a sequence (new in Swift 2.0)
If you have a sequence of optionals, you can use for case let _? to iterate over all the non-optional elements:
let a = ["0","1","foo","2"]
for case let i? in a.map({ Int($0)}) {
print(i+1, appendNewline: false)
}
prints 321. This is using the pattern-matching syntax for an optional, which is a variable name followed by ?.
You can also use this pattern matching in switch statements:
func add(i: Int?, _ j: Int?) -> Int? {
switch (i,j) {
case (nil,nil), (_?,nil), (nil,_?):
return nil
case let (x?,y?):
return x + y
}
}
add(1,2) // 3
add(nil, 1) // nil
Looping until a function returns nil
Much like if let, you can also write while let and loop until nil:
while let line = readLine() {
print(line)
}
You can also write while var (similar caveats to if var apply).
where clauses also work here (and terminate the loop, rather than skipping):
while let line = readLine()
where !line.isEmpty {
print(line)
}
Passing an optional into a function that takes a non-optional and returns a result
Instead of:
let j: Int
if i != nil {
j = abs(i!)
}
else {
// no reasonable action to take at this point
fatalError("no idea what to do now...")
}
you can use optional’s map operator:
let j = i.map { abs($0) }
This is very similar to optional chaining, but for when you need to pass the non-optional value into the function as an argument. As with optional chaining, the result will be optional.
This is nice when you want an optional anyway. For example, reduce1 is like reduce, but uses the first value as the seed, returning an optional in case the array is empty. You might write it like this (using the guard keyword from earlier):
extension Array {
func reduce1(combine: (T,T)->T)->T? {
guard let head = self.first
else { return nil }
return dropFirst(self).reduce(head, combine: combine)
}
}
[1,2,3].reduce1(+) // returns 6
But instead you could map the .first property, and return that:
extension Array {
func reduce1(combine: (T,T)->T)->T? {
return self.first.map {
dropFirst(self).reduce($0, combine: combine)
}
}
}
Passing an optional into a function that takes an optional and returns a result, avoiding annoying double-optionals
Sometimes, you want something similar to map, but the function you want to call itself returns an optional. For example:
// an array of arrays
let arr = [[1,2,3],[4,5,6]]
// .first returns an optional of the first element of the array
// (optional because the array could be empty, in which case it's nil)
let fst = arr.first // fst is now [Int]?, an optional array of ints
// now, if we want to find the index of the value 2, we could use map and find
let idx = fst.map { find($0, 2) }
But now idx is of type Int??, a double-optional. Instead, you can use flatMap, which “flattens” the result into a single optional:
let idx = fst.flatMap { find($0, 2) }
// idx will be of type Int?
// and not Int?? unlike if `map` was used

I think you should go back to the Swift programming book and learn what these things are for. ! is used when you are absolutely sure that the optional isn't nil. Since you declared that you are absolutely sure, it crashes if you're wrong. Which is entirely intentional. It is "unsafe and best avoided" in the sense that asserts in your code are "unsafe and best avoided". For example:
if someOptional != nil {
someFunction(someOptional!)
}
The ! is absolutely safe. Unless there is a big blunder in your code, like writing by mistake (I hope you spot the bug)
if someOptional != nil {
someFunction(SomeOptional!)
}
in which case your app may crash, you investigate why it crashes, and you fix the bug - which is exactly what the crash is there for. One goal in Swift is that obviously your app should work correctly, but since Swift cannot enforce this, it enforces that your app either works correctly or crashes if possible, so bugs get removed before the app ships.

You there is one way. It is called Optional Chaining. From documentation:
Optional chaining is a process for querying and calling properties,
methods, and subscripts on an optional that might currently be nil. If
the optional contains a value, the property, method, or subscript call
succeeds; if the optional is nil, the property, method, or subscript
call returns nil. Multiple queries can be chained together, and the
entire chain fails gracefully if any link in the chain is nil.
Here is some example
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
if let roomCount = john.residence?.numberOfRooms {
println("John's residence has \(roomCount) room(s).")
} else {
println("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms."
You can check the full article here.

We can use optional binding.
var x:Int?
if let y = x {
// x was not nil, and its value is now stored in y
}
else {
// x was nil
}

After lot of thinking and researching i have came up with the easiest way to unwrap an optional :
Create a new Swift File and name it UnwrapOperator.swift
Paste the following code in the file :
import Foundation
import UIKit
protocol OptionalType { init() }
extension String: OptionalType {}
extension Int: OptionalType {}
extension Int64: OptionalType {}
extension Float: OptionalType {}
extension Double: OptionalType {}
extension CGFloat: OptionalType {}
extension Bool: OptionalType {}
extension UIImage : OptionalType {}
extension IndexPath : OptionalType {}
extension NSNumber : OptionalType {}
extension Date : OptionalType {}
extension UIViewController : OptionalType {}
postfix operator *?
postfix func *?<T: OptionalType>( lhs: T?) -> T {
guard let validLhs = lhs else { return T() }
return validLhs
}
prefix operator /
prefix func /<T: OptionalType>( rhs: T?) -> T {
guard let validRhs = rhs else { return T() }
return validRhs
}
Now the above code has created 2 operator [One prefix and one postfix].
At the time of unwrapping you can use either of these operator before or after the optionals
The explanation is simple, the operators returns the constructor value if they get nil in variable else the contained value inside the variable.
Below is the example of usage :
var a_optional : String? = "abc"
var b_optional : Int? = 123
// before the usage of Operators
print(a_optional) --> Optional("abc")
print(b_optional) --> Optional(123)
// Prefix Operator Usage
print(/a_optional) --> "abc"
print(/b_optional) --> 123
// Postfix Operator Usage
print(a_optional*?) --> "abc"
print(b_optional*?) --> 123
Below is the example when variable contains nil :
var a_optional : String? = nil
var b_optional : Int? = nil
// before the usage of Operators
print(a_optional) --> nil
print(b_optional) --> nil
// Prefix Operator Usage
print(/a_optional) --> ""
print(/b_optional) --> 0
// Postfix Operator Usage
print(a_optional*?) --> ""
print(b_optional*?) --> 0
Now it is your choice which operator you use, both serve the same purpose.

Related

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

How to check if a UILabel is empty and append content to a label?

New to ios and swift. Want some best practice tips.
I want to append content to a label in a new line. My try:
#IBOutlet weak var history: UILabel!
#IBAction func appendContent() {
if history.text != nil && !history.text!.isEmpty {
history.text = history.text! + "\r\n" + "some content"
}
else{
history.text = digit
}
}
It seems to work, however,
Is there a better way to check the text is not nil and not empty?
Is there a "keyword" thing for "\r\n"?
You can use optional binding: if let to check if something is nil.
Example 1:
if let text = history.text where !text.isEmpty {
history.text! += "\ncontent"
} else {
history.text = digit
}
Or you can use map to check for optionals:
Example 2:
history.text = history.text.map { !$0.isEmpty ? $0 + "\ncontent" : digit } ?? digit
!$0.isEmpty is in most cases not even needed so the code can look a bit better:
history.text = history.text.map { $0 + "\ncontent" } ?? digit
EDIT: What does map do:
The map method solves the problem of transforming the elements of an array using a function.
Let’s say we have an array of Ints representing some sums of money and we want to create a new array of strings that contains the money value followed by the “€” character i.e. [10,20,45,32] -> ["10€","20€","45€","32€"].
The ugly way of doing this is by creating a new empty array, iterating our original array transforming each element and adding it to the new array
var stringsArray = [String]()
for money in moneyArray {
stringsArray += "\(money)€"
}
Using map is just:
let stringsArray = moneyArray.map { "\($0)€" }
It can also be used for optionals:
The existing map allows you to apply a function to the value inside an optional, if that optional is non-nil. For example, suppose you have an optional integer i and you want to double it. You could write i.map { $0 * 2 }. If i has a value, you get back an optional of that value doubled. On the other hand, if i is nil, no doubling takes place.
(source)
What does ?? do:
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.
The nil coalescing operator is shorthand for the code below:
a != nil ? a! : b
What about using something like this:
if let text = history.text where !text.isEmpty {
history.text = "\(text)\nsome content"
}

Two (or more) optionals in Swift

While watching an Apple's video about LLDB debugger I found something I can't find an explanation for; he was talking about optional values when he wrote:
var optional: String? = nil; //This is ok, a common optional
var twice_optional: String?? = nil; //What is this and why's this useful??
I opened a playground and started trying it out and realized that you can write as many as ? as you want, and then unwrap them with the same number of !. I understand the concept of wrapping/unwrapping a variable but can't think of a situation where I would like to wrap a value 4, 5 or 6 times.
(Updated for Swift >=3)
"Double optionals" can be useful, and the Swift blog entry "Optionals Case Study: valuesForKeys" describes an application.
Here is a simplified example:
let dict : [String : String?] = ["a" : "foo" , "b" : nil]
is a dictionary with optional strings as values. Therefore
let val = dict[key]
has the type String?? aka Optional<Optional<String>>. It is .none (or nil)
if the key is not present in the dictionary, and .some(x) otherwise. In the second
case, x is a String? aka Optional<String> and can be .none (or nil)
or .some(s) where s is a String.
You can use nested optional binding to check for the various cases:
for key in ["a", "b", "c"] {
let val = dict[key]
if let x = val {
if let s = x {
print("\(key): \(s)")
} else {
print("\(key): nil")
}
} else {
print("\(key): not present")
}
}
Output:
a: foo
b: nil
c: not present
It might be instructive to see how the same can be achieved with pattern matching
in a switch-statement:
let val = dict[key]
switch val {
case .some(.some(let s)):
print("\(key): \(s)")
case .some(.none):
print("\(key): nil")
case .none:
print("\(key): not present")
}
or, using the x? pattern as a synonym for .some(x):
let val = dict[key]
switch val {
case let (s??):
print("\(key): \(s)")
case let (s?):
print("\(key): nil")
case nil:
print("\(key): not present")
}
(I do not know a sensible application for more deeply nested optionals.)
var tripleOptional: String???
is same as
var tripleOptional: Optional<Optional<Optional<String>>>
I cannot think of any useful use of it, but its there because optionals are generic work for any type of object. Nested optionals are like box put into another box or array but into an other array.

Swift: How to write a variant of enumerate that takes an optional sequence type

I tried to add an override for enumerate that handles the case of an optional sequence (without crashing). The idea was that if the sequence is valid aka .Some, it would enumerate that sequence, otherwise enumerate an empty sequence:
func enumerate2<Seq : SequenceType>(base: Seq?) -> EnumerateSequence<Seq> {
// if optional sequence is specified
if let b = base { return enumerate(b) }
// enumerate empty sequence
let a = Array<Seq.Generator.Element>()
return Swift.enumerate(a)
}
func enumerate3<Seq : SequenceType, T where T == Seq.Generator.Element>(base: Seq?) -> EnumerateSequence<Seq> {
// if optional sequence is specified
if let b = base { return enumerate(b) }
// enumerate empty sequence
let a = Array<T>()
return Swift.enumerate(a)
}
I am seeing the error:
'Array<Seq.Generator.Element>' does not conform to protocol 'GeneratorType'
on the last return lines: return Swift.enumerate(a)
This confuses me as EnumerateSequence<Seq> does not appear to conform to GeneratorType. This seems like a simple enough exercise, what could I be missing?
Note that the above code is split apart for illustration, and the suffixes 2 and 3 are to keep remove ambiguity.
Edit:
One work around is to return an Optional sequence instead of an empty sequence.
func enumerate<Seq : SequenceType>(base: Seq?) -> EnumerateSequence<Seq>? {
return base != nil ? enumerate(base) : nil
}
The problem then shifts to safely enumerating optionals:
public func each<S:SequenceType, T where T == S.Generator.Element>
(seq: S, with fn:(T)->()) {
for s in seq { fn(s) }
}
public func each<S:SequenceType, T where T == S.Generator.Element>
(seq: S?, with fn:(T)->()) {
if let some = seq {
for s in some { fn(s) }
}
}
let es = enumerate(["a", "b", "c", "d"])
each(es) { p in
println("\(p.0), \(p.1)")
}
let b:[Int]? = nil
let nes = enumerate(b)
each(nes) { p in
println("\(p.0), \(p.1)")
}
println("done")
which produces:
0, a
1, b
2, c
3, d
done
Perhaps though, the explicit use of if let... is better just for being more obvious, but I am still curious about the initial compilation error.
This isn't working because your function declaration says you're returning an EnumerateSequence<Seq>, but that last line would return a EnumerateSequence <Array<Seq.Generator.Element>>—those aren't the same, so the compiler won't allow it.
You need to be able to create an empty instance of Seq type, but the SequenceType protocol doesn't specify an initializer - you need to go down the chain to ExtensibleCollectionType to find a protocol with an initializer, so change your generic constraint to that. Then you can do this:
func enumerate3<Seq : ExtensibleCollectionType>(base: Seq?) -> EnumerateSequence<Seq> {
// if optional sequence is specified
if let b = base { return enumerate(b) }
// enumerate empty sequence
let a = Seq()
return enumerate(a)
}
Note: if you look through the Swift headers, it won't show you that Array conforms to ExtensibleCollectionProtocol, but it actually does through a "hidden" ArrayType protocol.
There was a good solution to this posted on dev forurms.
The solution requires altering the return type and and using SequenceOf(EmptyCollection>(...)), but that does not appear to have any negative impact since the compiler will already differentiate based on the optional argument type. The code is:
func enumerate<Seq: SequenceType>(base: Seq?) -> SequenceOf<(Int, Seq.Generator.Element)> {
if let base = base {
return SequenceOf(Swift.enumerate(base))
} else {
return SequenceOf(EmptyCollection<(Int, Seq.Generator.Element)>())
}
}

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