Reputation: 2714
I want to unwrap two optionals in one if statement, but the compiler complaints about an expected expression after operator at the password constant. What could be the reason?
if let email = self.emailField?.text && let password = self.passwordField?.text
{
//do smthg
}
Done in Swift.
Upvotes: 67
Views: 32925
Reputation: 3386
Great news. Unwrapping multiple optionals in a single line is now supported in Swift 1.2 (XCode 6.3 beta, released 2/9/15).
No more tuple/switch pattern matching needed. It's actually very close to your original suggested syntax (thanks for listening, Apple!)
if let email = emailField?.text, let password = passwordField?.text {
}
Another nice thing is you can also add where
for a "guarding condition":
var email: String? = "[email protected]"
var name: String? = "foo"
if let n = name, let e = email where contains(e, "@") {
println("name and email exist, email has @")
}
Reference: XCode 6.3 Beta Release Notes
Upvotes: 138
Reputation: 1140
Swift 4
if let suggestions = suggestions, let suggestions1 = suggestions1 {
XCTAssert((suggestions.count > suggestions1.count), "TEST CASE FAILED: suggestion is nil. delete sucessful");
}
Upvotes: 4
Reputation: 1315
Update for Swift 3:
if let email = emailField?.text, let password = passwordField?.text {
}
each variable must now be preceded by a let keyword
Upvotes: 47
Reputation: 13768
Before Swift 1.2
Like @James, I've also created an unwrap
function, but this one uses the existing if let
for control flow, instead of using a closure:
func unwrap<T1, T2>(optional1: T1?, optional2: T2?) -> (T1, T2)? {
switch (optional1, optional2) {
case let (.Some(value1), .Some(value2)):
return (value1, value2)
default:
return nil
}
}
This can be used like so:
if let (email, password) = unwrap(self.emailField?.text, self.passwordField?.text)
{
// do something
}
From: https://gist.github.com/tomlokhorst/f9a826bf24d16cb5f6a3
Note that if you want to handle more cases (like when one of the two fields is nil), you're better off with a switch
statement.
Upvotes: 5
Reputation: 995
Based on @Joel's answer, I've created a helper method.
func unwrap<T, U>(a:T?, b:U?, handler:((T, U) -> ())?) -> Bool {
switch (a, b) {
case let (.Some(a), .Some(b)):
if handler != nil {
handler!(a, b)
}
return true
default:
return false
}
}
// Usage
unwrap(a, b) {
println("\($0), \($1)")
}
Upvotes: 0
Reputation: 271
How about wrapping the optionals in a tuple and using switch to pattern match?
switch (self.emailField?.text, self.passwordField?.text) {
case let (.Some(email), .Some(password)):
// unwrapped 'email' and 'password' strings available here
default:
break
}
It's definitely a bit noisier, but at least it could also be combined with a where clause as well.
Upvotes: 26
Reputation: 22487
The usage
if let x = y {
}
is not equivalent to
if (let x = y) { // this is actually not allowed
}
"if let" is effectively a two-word keyword, which is equivalent to
if y != nil {
let x = y!
// rest of if let block
}
Upvotes: 9
Reputation: 53101
I can't explain why the above code doesn't work, but this would be good a replacement:
if let email = self.emailField?.text
{
if let password = self.passwordField?.text
{
//do smthg
}
}
Upvotes: 1