Expected expression in conditional in let statement - swift

I am getting this error on the after the let statement. Does anyone know why I am getting this error?
#objc private func didtaploginbutton() {
passwordTextField.resignFirstResponder()
usernameTextField.resignFirstResponder()
guard let usernameEmail = usernameTextField.text, !usernameEmail.isEmpty,
let password = passwordTextField.text, !password.isEmpty, password.count >= 8, else do {
return
}
}

Remove the do. It's usually only used when you want to handle an error with a Do-Catch block. You might also want to break the expression into multiple lines, so that it's easier to read.
Also, you have an extra comma (,) before the else. You need to remove this.
guard
let usernameEmail = usernameTextField.text,
!usernameEmail.isEmpty,
let password = passwordTextField.text,
!password.isEmpty,
password.count >= 8
else { return }

Related

Swift: Multiple conditions in IF statement

I'm currently trying to validate a sign up page using an if statement with multiple conditions.
At the same time, I want to validate the email address with a correct email format.
Below is each field should essentially be checked.
#IBAction func createAccountButton(_ sender: Any) {
//check if textfields are empty and display alert
let providedEmailAddress = emailTextField.text
let isEmailAddressValid = isValidEmailAddress(emailAddressString: providedEmailAddress!)
if ( isEmailAddressValid || (firstNameTextField.text?.isEmpty)! || (lastNameTextField.text?.isEmpty)! || (usernameTextField.text?.isEmpty)! || (phoneNumberTextField.text?.isEmpty)! || (passwordTextField.text?.isEmpty)!) {
let alertViewController = SCLAlertView().showInfo("Failed to create account", subTitle: "One or more fields are empty, please check and try again.")
} else {
SVProgressHUD.show(withStatus: "Creating account...")
SVProgressHUD.dismiss(withDelay: 4)
}
}
The variable isEmailAddressValid is linked to this function I found on this site.
// Check if email address entered is of the valid format
func isValidEmailAddress(emailAddressString: String) -> Bool {
var returnValue = true
let emailRegEx = "[A-Z0-9a-z.-_]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,3}"
do {
let regex = try NSRegularExpression(pattern: emailRegEx)
let nsString = emailAddressString as NSString
let results = regex.matches(in: emailAddressString, range: NSRange(location: 0, length: nsString.length))
if results.count == 0
{
returnValue = false
}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
returnValue = false
}
return returnValue
}
However, when testing I realised when I enter a value in each field except the emailTextfield.text and click to create an account, the else part of the statement is executed.
Moreover when all fields have a value, I would assume the else part of the statement WILL execute, but the 'failed to create an account' alert is displayed instead.
What am I doing wrong and what needs to be changed?
You should replace this part
if ( isEmailAddressValid |
with
if ( !isEmailAddressValid |

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.

Forced unwrapping of optional causes crash in Filter

I am having trouble with this method; I am getting a "fatal error: unexpectedly found nil while unwrapping an Optional value" error.
let filtererArr = structArrayWithNoOptionals.filter({
return getFloatNumberFromPriceString(removeCommaFromPriceString($0.totalFare!)) >= minPrice && getFloatNumberFromPriceString(removeCommaFromPriceString($0.totalFare!)) <= maxPrice
})
How do I fix this to prevent it from crashing?
I always try to avoid force unwrapping when possible, in your case you can use guard let or if let to unwrap it
Change your code this
let filtererArr = structArrayWithNoOptionals.filter({
guard let totalFare = $0.totalFare else { return false }
return getFloatNumberFromPriceString(removeCommaFromPriceString(totalFare)) >= minPrice &&
getFloatNumberFromPriceString(removeCommaFromPriceString(totalFare)) <= maxPrice
})
Like Niko said (+1), you should avoid ! forced unwrapping. Perform optional binding via if let or guard let instead.
Personally, rather than using removeCommaFromPriceString and getFloatNumberFromPriceString, I'd probably use a NSNumberFormatter.
For example, in Swift 3:
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
let filtererArr = structArrayWithNoOptionals.filter {
guard let string = $0.totalFare, let totalFareValue = formatter.number(from: string)?.doubleValue else { return false }
return totalFareValue >= minPrice && totalFareValue <= maxPrice
}
The number formatter will automatically handle strings with thousands separators (which I assume is your intent of removing the commas), but it will also handle international number formats (e.g. in Germany, the thousands separator is . and the decimal point is ,).

Can I use "guard let" if you want to pass over an optional string to "rawValue:" in enum in 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
}

Swift-y boolean expression - case outside if/switch

To continue to the next screen, a patron must have one of two identifiers. The code I've got to do this is:
let identifier1Entered = !patron.identifier1.isEmpty
let identifier2Entered = patron.identifier2 != nil && !patron.identifier2!.isEmpty
guard identifier1Entered || identifier2Entered else { return }
But it's not Swifty, I'm force-unwrapping the optional identifier2, because I don't want to expand this to a longer, and IMO messier
var identifier2Entered = false
if let identifier2 = patron.identifier2 where !identifier2.isEmpty {
identifier2Entered = true
}
What I thought might work is just taking the expression out of the if statement, like:
let id2Entered = let identifier2 = patron.identifier2 where !identifier2.isEmpty
or
let id2Entered = case .Some(let id2) = patron.identifier2 where !id2.isEmpty
But it appears that these expressions are only allowed within if statements.
The other more Swifty solution I thought of is this:
let identifier1Entered = !patron.identifier1.isEmpty
guard let id2 = patron.identifier2 where !id2.isEmpty || identifier1Entered
else { return }
But it requires that identifier2 is not nil, which is incorrect, and as far as I know, there's no way to use optional binding with || in if or guard statements. Not to mention that I feel it's less clear and readable than the force-unwrapping.
Anyone have a clear, more Swifty solution?
Two possible solutions using optional chaining:
let identifier2Entered = patron.identifier2?.isEmpty == false
let identifier2Entered = !(patron.identifier2?.isEmpty ?? true)
If patron.identifier2 is nil then patron.identifier2?.isEmpty
evaluates to nil, and you'll get false as a result.