Why doesn't guard create unwrapped var? - ios

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)!

Related

Comparing two Doubles in Swift: "Type of expression is ambiguous without more context"

I have a function that must check if a value (realOperand) is bigger than other value (realValue). These values are numeric, but they come in string, and I parse them to Double:
return Double(realOperand) > Double(realValue)
I can't understand why, but that line is giving this error:
Type of expression is ambiguous without more context
The function
Double.init(_ string: String) returns an Optional (Type Double?).
It would be like you wrote this code:
var a: Double? = nil
var b: Double? = 7
if a > b {
print("A is greater")
}
Is nil greater than or less than 7? It's undefined. Optionals are not Comparable.
You need to decide what to do if either or both strings can't be converted to Double:
guard let operand = Double(realOperand),
value = Double(realValue) else {
// Crash on purpose. Not a great option for user-entered Strings!
fatalError("Could not convert strings to Doubles")
}
return operand > value
You can override the operator for comparing. Optional value.
As explained more in here you can not compare optional values.
func > <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs, let rhs = rhs {
return lhs > rhs
} else {
return false
}
}

How to implement a infix custom operator that handles optionality in swift

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

value?.min != nil ? value!.min : nil not force unwrapping writing Optional(some number)

func myFunc(array:[Int]) -> (min: Int, max: Int)?
{
if array.isEmpty {return nil}
var minNumber = array[0]
var maxNumber = array[0]
for number in array {
if number < minNumber {
minNumber = number
}
else if number > maxNumber{
maxNumber = number
}
}
return (minNumber, maxNumber)
}
let tempArray:[Int] = [1,2,3,4,5,6,7]
let value = myFunc(array: tempArray)
print("The minima is: \(value?.min != nil ? value!.min : nil) the maxima is \(value?.max != nil ? value!.max : nil)")
In the given code I just wanted to make if for example, the code contains some value it will force unwrap but if it is not contained it will just print "nil". But in my code, if it contains number it will print Optional(some number).
value?.min != nil ? value!.min : nil
is a (conditional) expression and evaluates to some value which has a type.
The first expression value!.min has the type Int, but the second expression nil is an optional and has the type Int?. Therefore the type of the conditional expression becomes Int? and that is printed as "Optional(1)".
What you want is the string "nil", or the non-nil value as a string:
print("The minimum is: \(value?.min != nil ? "\(value!.min)" : "nil")")
(and similarly for the maximum). Now both expression in the conditional expression
value?.min != nil ? "\(value!.min)" : "nil")
are strings, and the result is a string as well. This can be abbreviated to
print("The minimum is: \(value.map {"\($0.min)"} ?? "nil")")
If you need this frequently then you can define an extension method on the optional type
extension Optional {
var descriptionOrNil: String {
switch self {
case .some(let wrapped): return "\(wrapped)"
case .none: return "nil"
}
}
}
and use it as
print("The minimum is: \((value?.min).descriptionOrNil)")
So if i don't understand the question wrong. You can do:
extension Optional where Wrapped == Int {
var valueOrEmpty: String {
guard let unwrapped = self else {
return "nil"
}
return "\(unwrapped)"
}
}
print("The minima is: \(value?.min.valueOrEmpty) the maxima is \(value?.max.valueOrEmpty)")
Right?

Checking if `if let` is nil

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
}

Swift: Nil is incompatible with return type String

I have this code in Swift:
guard let user = username else{
return nil
}
But I'm getting the following errors:
Nil is incompatible with return type String
Any of you knows why or how I return nil in this case?
I'll really appreciate your help
Does your function declare an optional return type?
func foo() -> String? { ...
See more on: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
NOTE
The concept of optionals doesn’t exist in C or Objective-C. The
nearest thing in Objective-C is the ability to return nil from a
method that would otherwise return an object, with nil meaning “the
absence of a valid object.”
You have to tell the compiler that you want to return nil. How do you that? By assigning ? after your object. For instance, take a look at this code:
func newFriend(friendDictionary: [String : String]) -> Friend? {
guard let name = friendDictionary["name"], let age = friendDictionary["age"] else {
return nil
}
let address = friendDictionary["address"]
return Friend(name: name, age: age, address: address)
}
Notice how I needed to tell the compiler that my object Friend, which I'm returning, is an optional Friend?. Otherwise it will throw an error.
*Does your function declare an optional return type?
func minAndmax(array:[Int])->(min:Int, max:Int)? {
if array.isEmpty {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array {
if value < currentMin {
currentMin = value
}
else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minAndmax(array: [8, -6, 2, 109, 3, 71]) {
print(bounds)
}

Resources