Can I use "guard let" if you want to pass over an optional string to "rawValue:" in enum in Swift? - swift

I want to initialize a enum from a variable of type String?, like:
guard let rawId = request.queryParameters["id"] else {
return
}
guard let id = MyIdentifier(rawValue: rawId) else {
return
}
In this case, request.queryParameters["id"] returns String?. Then after I ensure that it is String in rawId, I convert it into an enum instance id.
However, the code is dirty and I want to write it in one-line if at all possible.
However, I don't like to make it unwrapped via forced optional unwrapping, because if it can not be transformed to String, the app would end up with an error, since rawValue: only takes String. I meant something like the following, which I don't like:
guard let id = MyIdentifier(rawValue: request.queryParameters["id"]!) else {
return
}
So is it still possible to define the guard let in one-line, maybe using where and/or case in guard?

You have two conditions there, trying to combine them into one condition is not always possible.
In your exact case I believe an empty id will behave the same as a nil id, therefore nil coalescing can be used:
guard let id = MyIdentifier(rawValue: request.queryParameters["id"] ?? "") else {
return
}
However, there is nothing dirty about splitting two checks into two statements. Code is not written to be short, it's written to be clear:
guard let rawId = request.queryParameters["id"],
let id = MyIdentifier(rawValue: rawId) else
return
}
Also, there is nothing wrong with creating a custom initializer for your enum:
init?(id: String?) {
guard let id = id else {
return nil
}
self.init(rawValue: id)
}
and then
guard let id = MyIdentifier(id: request.queryParameters["id"]) else {
return
}

Try this:
You can simply combine both the statements into a single statement ,i.e,
guard let id = request.queryParameters["id"], let id2 = MyIdentifier(rawValue: id) else {
return
}

Related

Forwarding function generic parameter to generic class type

I have created enum with associated value and I want to be able to dynamically update associated value. As far as I know Swift doesn't support that at the moment.
Because of that I used following approach:
enum PersonInfo {
class EnumValue<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
// Instead of using String or Bool or any other type directly, use EnumValue wrapper
case firstName(EnumValue<String>)
case lastName(EnumValue<String>)
case isAdult(EnumValue<Bool>)
}
I want to add function that would update EnumValue.value property in following way:
func updateAssociatedValue<V>(_ updateValue: V) {
let mirror = Mirror(reflecting: self)
for associatedValue in mirror.children {
guard let value = associatedValue.value as? EnumValue<V> else {
continue
}
value.value = updateValue
}
}
Problem is that this guard statement always fails (guard let value = associatedValue.value as? EnumValue<V>) and I can't figure it out why.
On the other hand, when I write updateAssociatedValue with typed type then things work properly:
// This works
func updateAssociatedValue(_ updateValue: String) {
let mirror = Mirror(reflecting: self)
for associatedValue in mirror.children {
guard let value = associatedValue.value as? EnumValue<String> else {
continue
}
value.value = updateValue
}
}
Things compile normally but during the runtime guard statement always fails. Am I using generic value in some incorrect way? Should I use somehow updateValue.Type or updateValue.self (I tried but it didn't work).
Example of usage:
var array: [PersonInfo] = [
.firstName(PersonInfo.EnumValue("John")),
.lastName(PersonInfo.EnumValue("Doe")),
.isAdult(PersonInfo.EnumValue(false))
]
print(array)
// John, Doe, false
array.first?.updateAssociatedValue("Mike")
print(array)
// Mike, Doe, false
I can always reassign enum value in array but if possible I want to avoid that. That's the reason for asking this question.

if let with try? gives optional value [duplicate]

I am using an SQLite library in which queries return optional values as well as can throw errors. I would like to conditionally unwrap the value, or receive nil if it returns an error. I'm not totally sure how to word this, this code will explain, this is what it looks like:
func getSomething() throws -> Value? {
//example function from library, returns optional or throws errors
}
func myFunctionToGetSpecificDate() -> Date? {
if let specificValue = db!.getSomething() {
let returnedValue = specificValue!
// it says I need to force unwrap specificValue,
// shouldn't it be unwrapped already?
let specificDate = Date.init(timeIntervalSinceReferenceDate: TimeInterval(returnedValue))
return time
} else {
return nil
}
}
Is there a way to avoid having to force unwrap there? Prior to updating to Swift3, I wasn't forced to force unwrap here.
The following is the actual code. Just trying to get the latest timestamp from all entries:
func getLastDateWithData() -> Date? {
if let max = try? db!.scalar(eventTable.select(timestamp.max)){
let time = Date.init(timeIntervalSinceReferenceDate: TimeInterval(max!))
// will max ever be nil here? I don't want to force unwrap!
return time
} else {
return nil
}
}
Update: As of Swift 5, try? applied to an optional expression does not add another level of optionality, so that a “simple” optional binding is sufficient. It succeeds if the function did not throw an error and did not return nil. val is then bound to the unwrapped result:
if let val = try? getSomething() {
// ...
}
(Previous answer for Swift ≤ 4:) If a function throws and returns an optional
func getSomething() throws -> Value? { ... }
then try? getSomething() returns a "double optional" of the
type Value?? and you have to unwrap twice:
if let optval = try? getSomething(), let val = optval {
}
Here the first binding let optval = ... succeeds if the function did
not throw, and the second binding let val = optval succeeds
if the return value is not nil.
This can be shortened with case let pattern matching to
if case let val?? = try? getSomething() {
}
where val?? is a shortcut for .some(.some(val)).
I like Martin's answer but wanted to show another option:
if let value = (try? getSomething()) ?? nil {
}
This has the advantage of working outside of if, guard, or switch statements. The type specifier Any? isn't necessary but just included to show that it returns an optional:
let value: Any? = (try? getSomething()) ?? nil

Optional Binding followed by casting to an optional in swift

I'm trying to parse data from a dictionary. I have code that currently works but I think there is a better more concise way to do it.
I have three options for what my dictionary can equal
let dictionary:[String:Any] = ["pic":"picture"] //opt1
let dictionary:[String:Any] = ["pic":2] //opt2
let dictionary:[String:Any] = ["pi":"this"] //opt3
This is the code that I am currently using to parse the data that I would like to be improved.
let _pic = dictionary["pic"]
if _pic != nil && !(_pic is String) {
print("error")
return
}
let pic = _pic as? String
For each option i'd like different things to happen for:
opt1
pic:String? = Optional(picture)
opt2 An error to be shown
opt3
pic:String? = nil
You can try this,
guard let _pic = dictionary["pic"] as? String else { return }
let _pic = dictionary["pic"]
This by default gives you an optional value for _pic that's of type Any?. As such, your code seems OK based on your requirements and I don't think you need the last line let pic = _pic as? String
I think you need to do two tests. Here's one way:
guard let picAsAny = dictionary["pic"]
else { /* No key in the dictionary */ }
guard let pic = picAsAny as? String
else { /* error wrong type */ }
// pic is now a (nonoptional) string
Obviously you can use if statements instead of guards depending on context.

Function throws AND returns optional.. possible to conditionally unwrap in one line?

I am using an SQLite library in which queries return optional values as well as can throw errors. I would like to conditionally unwrap the value, or receive nil if it returns an error. I'm not totally sure how to word this, this code will explain, this is what it looks like:
func getSomething() throws -> Value? {
//example function from library, returns optional or throws errors
}
func myFunctionToGetSpecificDate() -> Date? {
if let specificValue = db!.getSomething() {
let returnedValue = specificValue!
// it says I need to force unwrap specificValue,
// shouldn't it be unwrapped already?
let specificDate = Date.init(timeIntervalSinceReferenceDate: TimeInterval(returnedValue))
return time
} else {
return nil
}
}
Is there a way to avoid having to force unwrap there? Prior to updating to Swift3, I wasn't forced to force unwrap here.
The following is the actual code. Just trying to get the latest timestamp from all entries:
func getLastDateWithData() -> Date? {
if let max = try? db!.scalar(eventTable.select(timestamp.max)){
let time = Date.init(timeIntervalSinceReferenceDate: TimeInterval(max!))
// will max ever be nil here? I don't want to force unwrap!
return time
} else {
return nil
}
}
Update: As of Swift 5, try? applied to an optional expression does not add another level of optionality, so that a “simple” optional binding is sufficient. It succeeds if the function did not throw an error and did not return nil. val is then bound to the unwrapped result:
if let val = try? getSomething() {
// ...
}
(Previous answer for Swift ≤ 4:) If a function throws and returns an optional
func getSomething() throws -> Value? { ... }
then try? getSomething() returns a "double optional" of the
type Value?? and you have to unwrap twice:
if let optval = try? getSomething(), let val = optval {
}
Here the first binding let optval = ... succeeds if the function did
not throw, and the second binding let val = optval succeeds
if the return value is not nil.
This can be shortened with case let pattern matching to
if case let val?? = try? getSomething() {
}
where val?? is a shortcut for .some(.some(val)).
I like Martin's answer but wanted to show another option:
if let value = (try? getSomething()) ?? nil {
}
This has the advantage of working outside of if, guard, or switch statements. The type specifier Any? isn't necessary but just included to show that it returns an optional:
let value: Any? = (try? getSomething()) ?? nil

How to test the Optionality of a String?

I have two different scenarios where I need to test the "optionality" of an optional type. I have not been able to figure how to explicitly test if the variable is a .None or a .Some other than with an unwieldy switch statement. How can I test for Someness with an if statement?
Scenario 1
I am writing an address formatter and my inputs are a number of String? types. In this example a simple test for (str != nil) will work. However, since my other need is when dealing with a 'double optional' and a nil test can't distinguish between .Some(.None) and .None a solution to this problem will solve that problem too.
Here's a version that works using a switch
let address1:String? = "123 Main St"
let address2:String? = nil
let apt:String? = "101"
let components = [address1, address2, apt].filter( { (c) -> Bool in
switch c {
case .Some: return true
case .None: return false
}
}).map { return $0! } //Had to map because casting directly to [String] crashes
print(", ".join(components)) //"123 Main St, 101"
What's I'd like to see is something like with an if:
let nice = ["123 Main St", nil, "303"].filter { (c) -> Bool in
return (c == .Some)
}
print(", ".join(nice))
Scenario 2
This is where a nil test won't work. If something is a String?? it can be any of .None, .Some(.None), or .Some(.Some(String)). In my case, the variable is carrying the recordID from an api call which might either be missing entirely (.None), a value (.Some(.Some("ABDEFG")), or explicitly NULL (.Some(.None)).
let teamNoneNone: String?? = .None
let teamSomeNone: String?? = .Some(.None)
let teamSomeSome: String?? = "My favorite local sportsball team"
if teamNoneNone == nil {
print("teamNoneNone is nil but is it .None? We don't know!") //prints
} else {
print("teamNoneNone is not nil")
}
if teamSomeNone == nil {
print("teamSomeNone is nil")
} else {
print("teamSomeNone is not nil but is it .Some(.None)? We don't know!") //prints
}
if teamSomeSome == nil {
print("teamSomeSome is nil but is it .None? We don't know!")
} else {
print("teamSomeSome is not nil but is it .Some(.None) or .Some(.Some())? We don't know!") //prints
}
Via another SO post I found a workaround like this, but it's not very clear what's happening to a casual reader:
if let team: String? = teamSomeNone {
print("teamSomeNone is Some(.None)") //prints
} else {
print("teamSomeNone is .Some(.Some())")
}
if let tests if a value is .None, and if it isn’t, it unwraps it and binds it to a local variable within an if statement.
Using switch with .Some and .None is really a secondary way of handling optionals, if if let doesn’t cut it. But it almost always does, especially now you can do multiple if lets in a single statement, following the latest release of Swift 1.2 to production.
Wanting to filter out the nils in a collection is a common-enough task that Haskell has a standard function for it, called catMaybe. Here’s a version, which I’ll call catSome, that would do the trick in Swift:
func catSome<T>(source: [T?]) -> [T] {
var result: [T] = []
// iterate over the values
for maybe in source {
// if this value isn’t nil, unwrap it
if let value = maybe {
// and append it to the array
result.append(value)
}
}
return result
}
let someStrings: [String?] = ["123 Main St", nil, "101"]
catSome(someStrings) // returns ["123 Main St", "101"]
Doubly-wrapped optionals are a bit of a pain, so the best solution is to avoid them in the first place – often, via use of optional chaining or flatMap.
But if you do find yourself with some, and all you care about is the inner value, you can unwrap them using a double if let:
// later parts of the let can rely on the earlier
if let outer = teamSomeSome, teamName = outer {
println("Fully unwrapped team is \(teamName)")
}
If you want to explicitly know if a double-optional has an inner nil inside an outer value, but isn’t nil itself, you can use if let with a where clause:
if let teamSomeMaybe = teamSomeNone where teamSomeMaybe == nil {
// this will be executed only if it was .Some(.None)
println("SomeNone")
}
The where clause is an extra conditional that can be applied to the unwrapped value.