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
Related
I'm trying to implement a custom operator for Collections similar to the Elvis operator (?: in kotlin, ?? in swift), but in addition to checking nullability, the operator also checks if the collection is Empty.
However, when I try to use the operator, the code doesn't compile. The compiler throws an "ambiguous use of operator" error.
The implementation of the ?? operator in the swift language seems to be really similar to mine, so I'm a little lost.. Any help to understand why this happens, and how to fix it, will be greatly appreciated.
/// Returns the first argument if it's not null and not empty, otherwise will return the second argument.
infix operator ?/ : NilCoalescingPrecedence
#inlinable func ?/ <T: Collection>(optional: T?, defaultValue: #autoclosure () throws -> T) rethrows -> T {
if let value = optional,
!value.isEmpty {
return value
} else {
return try defaultValue()
}
}
#inlinable func ?/ <T: Collection>(optional: T?, defaultValue: #autoclosure () throws -> T?) rethrows -> T? {
if let value = optional,
!value.isEmpty {
return value
} else {
return try defaultValue()
}
}
func test() {
let optionalValue: String? = nil
let value1: String = optionalValue ?? "default value" // This works
let value2: String = optionalValue ?/ "default value" // This works
let value3: String? = optionalValue ?/ nil // This works
let value4: String? = optionalValue ?? nil // This works
let value5: String? = optionalValue ?? "default value" // This works
let value6: String? = optionalValue ?/ "default value" // This dont compile: Ambiguous use of operator '?/'
}
The standard implementation for the ?? operator can be found at: https://github.com/apple/swift/blob/main/stdlib/public/core/Optional.swift, just search for "?? <" in the browser.
Maybe I'm using the wrong approach to solve this problem. If anyone knows a better solution will be great too.
Short answer, you can't do that.
Probably ??, provided by swift, works because swift has it's own powers and it treats these situations on it's own.
But for our code, it doesn't work like that.
What will happen there is:
For the expression: let value2: String = optionalValue ?/ "default value".
First the compiler will look to the optionalValue parameter and will find 2 methods that accept an optional as first parameter;
Then it will look to the second parameter (defaultValue) that is a closure returning a non-optional T: Collection instance, and it will filter and match the first operator overload;
The last thing is the return value that is a non-optional T: Collection instance, and the first method is complient;
Success;
For the expression: let value4: String? = optionalValue ?/ "default value".
First the compiler will look to the optionalValue parameter and will find 2 methods that accept an optional as first parameter;
Then it will look to the second parameter (defaultValue) that is a closure returning an optional T: Collection aka Optional<T> where T: Collection instance, and then it will find 2 options for the 2 parameters so far;
At this point it will look for the return type of the function, but it will fail too;
Compiler error;
The reason that it fails is that T: Collection in your code is translated to String.
And for the defaultValue return type an non-optional String fits the first and second methods, leading the compiler to be unsure which one it should use.
let string: String? = "value" and let string: String? = Optional<String>.init("value") are the same thing for the compiler due to implicit conversions that Swift does.
So there is not way to make this work from where my knowledge stands right now.
It turns out that swift has an attribute called #_disfavoredOverload, when I use it on the second method, everything works as intended.
Now the implementation of the second method is:
#_disfavoredOverload
#inlinable func ?/ <T: Collection>(optional: T?, defaultValue: #autoclosure () throws -> T?) rethrows -> T? {
if let value = optional,
!value.isEmpty {
return value
} else {
return try defaultValue()
}
}
Discovered this on the swift forum: https://forums.swift.org/t/how-to-implement-a-infix-custom-operator-that-handles-optionality-in-swift/47260/3
Based on the implementation, optionalValue ?/ "default value" will never return nil.
So you can do one of these:
Don't use optional if you know it will be not optional: (RECOMENDED)
let value6: String = optionalValue ?/ "default value"
Make it optional:
let value6: String? = (optionalValue ?/ "default value")!
Make it use the second function:
let anotherOptionalValue: String? = "default value"
let value6: String? = (optionalValue ?/ anotherOptionalValue
Use #_disfavoredOverload on the second function: (PROHABITED)
#_disfavoredOverload
#inlinable func ?/ <T: Collection>(optional: T?, defaultValue: #autoclosure () throws -> T?) rethrows -> T? { ... }
⚠️ Attributes marked with _ is not designed for general use!
Note:
Try using type inference. So your code will be more optimized and the compiler will have fewer issues to worry about.
let value6 = optionalValue ?/ "default value"
let value7 = optionalValue ?/ anotherOptionalValue
Without _disfavoredOverload, your original value6 needed a .some(...) on the RHS to disambiguate.
As you said "Maybe I'm using the wrong approach to solve this problem", I would suggest a different kind of solution. Instead of:
if let value = optional,
!value.isEmpty {
return value
} else {
return try defaultValue()
}
Let's write this:
value.ifNotEmpty ?? defaultValue()
Extend collection like so:
extension Collection {
var ifNotEmpty: Self? {
isEmpty ? nil : self
}
}
extension Optional where Wrapped: Collection {
var isEmpty: Bool {
map(\.isEmpty) ?? true
}
var ifNotEmpty: Self {
isEmpty ? nil : self
}
}
Now we don't need the custom operator, and that means the call sites can read like optionalValue.ifNotEmpty ?? "default value":
let optionalValue: String? = ""
let value1: String = optionalValue.ifNotEmpty ?? "default value"
let value3: String? = optionalValue.ifNotEmpty
let value5: String? = optionalValue.ifNotEmpty ?? "default value"
Depending on your preference, maybe this reads more clearly than the ?/ operator
But you also get to play nicely with unwrapping:
if let foo = optionalValue.ifNotEmpty {
...
}
This question already has an answer here:
Swift 3 incorrect string interpolation with implicitly unwrapped Optionals
(1 answer)
Closed 5 years ago.
let allPlaces = resultsArray.map({ (param) -> Places in
return Places(dictionary: param )
})
print("All Places \(allPlaces[0].placeName)")
The output of the above code is:
All Places Optional("Subway")
In the below code the var is not optional. But the print statement prints it as Optional. Should it not print All Places "Subway"?
class Places: NSObject {
var name:String!
init(dictionary:Dictionary<String, Any>) {
name = dictionary["name"] as? String
}
}
var name:String!
You have declared name as implicitly unwrapped optional. From Swift 3 onwards it will only be force unwrapped if they need to be type checked locally. Otherwise it will be treated as normal optional only.
print("All Places \(allPlaces[0].name)")
Here there is no type checking involved, so name would be still Optional.
If you do like
let name:String = allPlaces[0].name
print("All Places \(name)")
Output will be "All Places Subway"
or you need to force unwrap it
print("All Places \(allPlaces[0].name!)")
This would cause crash if the name is nil, you should take care of it. If there is a chance name can be nil then use var name: String? so compiler force you to unwrap explicitly.
Change 'as?' to 'as!'.
The exclamation point means it absolutely clear.
The question mark means optional binding.
[Source]
class Places: NSObject {
var name:String!
init(dictionary:Dictionary<String, Any>) {
name = dictionary["name"] as! String
}
}
Another way
print("All Places \(allPlaces[0].placeName)")
to
print("All Places \(allPlaces[0].placeName!)")
or
print("All Places \(allPlaces[0].placeName ?? "")")
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 ?? "")
}
How do you properly unwrap both normal and implicit optionals?
There seems to be confusion in this topic and I would just like to have a reference for all of the ways and how they are useful.
There are currently two ways to create optionals:
var optionalString: String?
var implicitOptionalString: String!
What are all the ways to unwrap both? Also, what is the difference between using ! and ? during the unwrapping?
There are many similarities and just a handful of differences.
(Regular) Optionals
Declaration: var opt: Type?
Unsafely unwrapping: let x = opt!.property // error if opt is nil
Safely testing existence : if opt != nil { ... someFunc(opt!) ... } // no error
Safely unwrapping via binding: if let x = opt { ... someFunc(x) ... } // no error
Using new shorthand: if let opt { ... someFunc(opt) ... } // no error
Safely chaining: var x = opt?.property // x is also Optional, by extension
Safely coalescing nil values: var x = opt ?? nonOpt
Implicitly Unwrapped Optionals
Declaration: var opt: Type!
Unsafely unwrapping (implicit): let x = opt.property // error if opt is nil
Unsafely unwrapping via assignment:
let nonOpt: Type = opt // error if opt is nil
Unsafely unwrapping via parameter passing:
func someFunc(nonOpt: Type) ... someFunc(opt) // error if opt is nil
Safely testing existence: if opt != nil { ... someFunc(opt) ... } // no error
Safely chaining: var x = opt?.property // x is also Optional, by extension
Safely coalescing nil values: var x = opt ?? nonOpt
Since Beta 5 we have also the new coalescing operator (??):
var a : Int?
let b : Int = a ?? 0
If the optional is != nil it is unwrapped else the value on the right of the operator is used
I created an approach to unwrap optional value:
// MARK: - Modules
import Foundation
import UIKit
import CoreData
// MARK: - PROTOCOL
protocol OptionalType { init() }
// MARK: - EXTENSIONS
extension String: OptionalType {}
extension Int: OptionalType {}
extension Double: OptionalType {}
extension Bool: OptionalType {}
extension Float: OptionalType {}
extension CGFloat: OptionalType {}
extension CGRect: OptionalType {}
extension UIImage: OptionalType {}
extension IndexPath: OptionalType {}
extension Date: OptionalType {}
extension UIFont: OptionalType {}
extension UIColor: OptionalType {}
extension UIViewController: OptionalType {}
extension UIView: OptionalType {}
extension NSMutableDictionary: OptionalType {}
extension NSMutableArray: OptionalType {}
extension NSMutableSet: OptionalType {}
extension NSEntityDescription: OptionalType {}
extension Int64: OptionalType {}
extension CGPoint: OptionalType {}
extension Data: OptionalType {}
extension NSManagedObjectContext: OptionalType {}
prefix operator ?*
//unwrapping values
prefix func ?*<T: OptionalType>( value: T?) -> T {
guard let validValue = value else { return T() }
return validValue
}
You can add your custom data type also.
Usage:-
var myString = ?*str
Hope it helps :)
An optional type means that the variable might be nil.
Example:
var myString: Int? = 55
myString = nil
The question mark indicates it might have nil value.
But if you state like this:
var myString : Int = 55
myString = nil
It will show error.
Now to retrieve the value you need to unwrap it:
print(myString!)
But if you want to unwrap automatically:
var myString: Int! = 55
Then:
print(myString)
No need to unwrap. Hope it will help.
You can also create extensions for particular type and unwrap safely with default value. I did the following for the same :
extension Optional where Wrapped == String {
func unwrapSafely() -> String {
if let value = self {
return value
}
return ""
}
}
Code sample of Safely unwrapping using binding:
let accountNumber = account.accountNumber //optional
let accountBsb = account.branchCode //optional
var accountDetails: String = "" //non-optional
if let bsbString = account.branchCode, let accString = account.accountNumber {
accountDetails = "\(bsbString) \(accString)" //non-optional
}
Unwrap optionals safely in Swift 5.7 ⛑
Different techniques (in order of preference)
Use the right tool for the job:
Optional chaining
guard let
if let
Nil coalescing operators
There are many ways to unwrap optional values safely in Swift. My reasons for ordering the techniques in my preferences above:
We should only unwrap optionals if we truly need to. In this case, we don't need to unwrap it and can use optional chaining. e.g. let value = optional?.value
Guard statements are helpful to exit the flow early when there's a precondition. It's the cleanest solution in many cases by reducing the levels of nesting.
if let may be more readable for sequential logic. In some cases, if let is more readable than guards when we don't want to exit a function but continue with additional logic outside the unwrapping block. if let is flexible and can also be used with similar syntax as guard statements.
We can use multiple guard statements to unwrap multiple optionals before using them, or even use ,, && or || to check multiple conditionals in a single guard.
Nil coalescing operators work well to cleanly unwrap optionals with a default value: ??. Don't overuse them though because using a guard is often clearer to exit early.
I've outlined the improved syntax for if let and guard let (much cleaner in Swift 5.7).
Force unwrapping or IUOs (Implicity Unwrapped Optionals) can lead to runtime crashes. They are indicated by a ! and are an anti-pattern in iOS unless part of a tests suite because they can crash if the optional is nil. In this case, we aren't leveraging Swift's improved type system over Objective-C. In tests, we don't care about clean code because the tests won't run in production and their purpose is contained.
New syntax for if let and guard
var x: EnumExample?
if let x {
print(x.rawValue) // No longer optional
}
// We can still explicitly name the `if let` value if we want.
if let value = x {
print(value.rawValue)
}
guard let x else {
return
}
print(x.rawValue) // No longer optional
guard let value = x else {
return
}
print(value.rawValue)
print(x?.rawValue ?? 0) // Unwrap with nil coalescing
NOTE: I also find Optional chaining a clean alternative to unwrapping optionals, and using x != nil sufficient for instances where we only need to check for existence. This is out of scope of the question for unwrapping optionals though.
There is only seven ways to unwrap an optional in Swift
var x : String? = "Test"
1,Forced unwrapping — unsafe.
let a:String = x!
2,Implicitly unwrapped variable declaration — unsafe in many cases.
var a = x!
3,Optional binding — safe.
if let a = x {
print("x was successfully unwrapped and is = \(a)")
}
4,Optional chaining — safe.
let a = x?.count
5,Nil coalescing operator — safe.
let a = x ?? ""
6,Guard statement — safe.
guard let a = x else {
return
}
7,Optional pattern — safe.
if case let a? = x {
print(a)
}
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
}