Avoid consecutive if let declarations in Swift
I wrote a little essay on the alternatives some time ago: https://gist.github.com/pyrtsa/77978129090f6114e9fb
One approach not yet mentioned in the other answers, which I kinda like, is to add a bunch of overloaded every
functions:
func every<A, B>(a: A?, b: B?) -> (A, B)? {
switch (a, b) {
case let (.Some(a), .Some(b)): return .Some((a, b))
default: return .None
}
}
func every<A, B, C>(a: A?, b: B?, c: C?) -> (A, B, C)? {
switch (a, b, c) {
case let (.Some(a), .Some(b), .Some(c)): return .Some((a, b, c))
default: return .None
}
}
// and so on...
These can be used in if let
statements, case
expressions, as well as optional.map(...)
chains:
// 1.
var foo: Foo?
if let (name, phone) = every(parsedName, parsedPhone) {
foo = ...
}
// 2.
switch every(parsedName, parsedPhone) {
case let (name, phone): foo = ...
default: foo = nil
}
// 3.
foo = every(parsedName, parsedPhone).map{name, phone in ...}
Having to add the overloads for every
is boilerplate'y but only has to be done in a library once. Similarly, with the Applicative Functor approach (i.e. using the <^>
and <*>
operators), you'd need to create the curried functions somehow, which causes a bit of boilerplate somewhere too.
Using multiple let-as within a if-statement in Swift
Update for Swift 3:
The following will work in Swift 3:
if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
// latitudeDouble and longitudeDouble are non-optional in here
}
Just be sure to remember that if one of the attempted optional bindings fail, the code inside the if-let
block won't be executed.
Note: the clauses don't all have to be 'let' clauses, you can have any series of boolean checks separated by commas.
For example:
if let latitudeDouble = latitude as? Double, importantThing == true {
// latitudeDouble is non-optional in here and importantThing is true
}
Swift 1.2:
Apple may have read your question, because your hoped-for code compiles properly in Swift 1.2 (in beta today):
if let latitudeDouble = latitude as? Double, longitudeDouble = longitude as? Double {
// do stuff here
}
Swift 1.1 and earlier:
Here's the good news - you can totally do this. A switch statement on a tuple of your two values can use pattern-matching to cast both of them to Double
at the same time:
var latitude: Any! = imageDictionary["latitude"]
var longitude: Any! = imageDictionary["longitude"]
switch (latitude, longitude) {
case let (lat as Double, long as Double):
println("lat: \(lat), long: \(long)")
default:
println("Couldn't understand latitude or longitude as Double")
}
Update: This version of the code now works properly.
How to avoid multiple if let statements in Swift 2
There are several solutions:
guard
- multiple
let
/var
inside the sameif
- params with default values
- ternary conditional operator
- Nil Coalescing Operator
- Don't accept optional params in the
init
(as suggested by nhgrif)
Looking at your example it seems that
self.title
self.initMainText
self.initBtnTitle
are optionals so you could simply write:
init(title: String?, mainText: String?, buttonTitle: String?) {
self.title = title
self.initMainText = mainText
self.initBtnTitle = buttonTitle
...
}
Using if let... with many expressions
Update for Swift 1.2
Since Swift 1.2, if let
allows unwrapping multiple optionals, so you can now just write this, as in your example:
if let x = someDict[someKey], y = someDict[someOtherKey] { … }
You can even interleave conditions such as:
if let x = someDict[someKey] where x == "value", y = someDict[someOtherKey] { … }
This used to be valid before Swift 1.2
Here's how you would do it without an ugly force-upwrapping:
switch (dict["a"], dict["b"]) {
case let (.Some(a), .Some(b)):
println("match")
default:
println("no match")
}
Still pretty verbose, actually.
This works because an optional type of the form Type?
is actually shorthand for Optional<Type>
, which is an enum that looks roughly like this:
enum Optional<T> {
case None
case Some(T)
}
You can then use pattern matching as for any other enum.
Edit: I've seen people write helper functions like this one (sorry for the lack of attribution, I don't remember where I saw it):
func unwrap<A, B>(a: A?, b: B?) -> (A, B)? {
switch (a, b) {
case let (.Some(a), .Some(b)):
return (a, b)
default:
return nil
}
}
Then you can keep using the if let
construct, namely like this:
if let (a, b) = unwrap(dict["a"], dict["b"]) {
println("match: \(a), \(b)")
} else {
println("no match")
}
Multiple if let and OR condition in swift
if let value1 = profile.value1, value1 != “” {}
else if value2 = profile.value2, value2 != “” {}
else if value3 = profile.value3, value3 != “” {}
here ,
acts like &&
Pay attention:
For Swift 2 replace ,
with where
Why do I get consecutive declarations on a line must be separated by and variable used within its own initial variable
Executable code, like if let urlPath = ...
, cannot go at the top level of a class declaration like you have it. It must go inside a function declaration.
Related Topics
Detecting iOS Dark Mode Change
Accessing a String Enum by Index
Swift Remove Object from Realm
How to Create a Cgsize in Swift
"Nsurl" Is Not Implicitly Convertible to "Url"; Did You Mean to Use "As" to Explicitly Convert
How to Make a Uiview Focusable Using the Focus Engine on Apple Tv
iOS 10 App Crashes When Trying to Save Image to Photo Library
How to Handle Touch Gestures in Swiftui in Swift Uikit Map Component
Single and Double Taps on Uitableviewcell in Swift 3
Binary Operator '==' Cannot Be Applied to Two Operands
Swift: Function with Default Parameter Before Non-Default Parameter
How to Color/Customize the Uiimagepickercontroller's Navigation Bar
Get Playground to Display All Loop Results
Dispatchqueue:Cannot Be Called with Ascopy = No on Non-Main Thread
Swiftui: How to Iterate Over an Array of Bindable Objects
How to Add Auto-Complete Comment in Xcode (Swift)
Checking If a Swift Class Conforms to a Protocol and Implements an Optional Function