How to check for quotations in swift 4? - swift

I am trying to check for string if it contains a single quotation or a double quotation
I tried using the following code but when I test and enter in the text field a single or double quotation , it passes as if there is no quotation.
var usernameSQL = username.text?.contains("\'") as! Bool || username.text?.contains("\"") as! Bool
guard !usernameSQL else {
let alertVC = UIAlertController(title: "Invlalid symbols", message: "(') and (\") symbols are not allowed", preferredStyle: .alert)
alertVC.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.show(alertVC, sender: nil)
return
}
print("passed")
What I get is "passed" being printed instead of getting alert "Invalid symbols".
Thanks in advance.

I think you are overcomplicating things.
You can easily achieve the same result with this small refactor.
if let textValue = username.text {
if textValue.contains("\'") || textValue.contains("\"") {
print("Show Alert")
} else {
print("Passed")
}
} else {
print("username.text is nil do something or just ignore")
}
Hope it helps.

A smarter solution is to use CharacterSet and rangeOfCharacter(from:. The benefit is the optional doesn't need to be unwrapped.
If there are no quotes the expression returns nil and passes the guard.
let quoteSet = CharacterSet(charactersIn: "\'\"")
guard username.text?.rangeOfCharacter(from: quoteSet) == nil else { ...
However I would take Larme's advice and create the character set with the allowed characters.

Related

Swift: How to properly write UIAlertAction with textfield and textview validation?

I am creating an app with one of the tab being a guestbook where users can write something. I use an UIAlertController to pop up a window with a textfield for entering name, and a textview for entering the message. I want to make the "Post" button disabled by default, then enable it after the name field has at least 2 characters and the message has at least 3 characters. I have achieved this by
#1: declare the "Post" UIAlertAction at the top
let saveAction = UIAlertAction(title:"Post", style: .default, handler: { (action) -> Void in print(data) })
The above line gives the error (Cannot use instance member 'data' within property initializer; property initializers run before self is available.)
#2: add this "Post" button in alert and making it disabled
alert.addAction(saveAction)
saveAction.isEnabled = false
#3 add two functions to detect how many words are in the textfield and textview, and if they meet the requirement, enable the "Post" button
func textViewDidChange(_ textView: UITextView) { //Handle the text changes here
GuestbookContentWordCount = textView.text.count
data["content"] = textView.text
enableSave()
}
#objc func textFieldDidChange(_ textField: UITextField) {
GuestbookNameWordCount = textField.text?.count ?? 0
data["name"] = textField.text
enableSave()
}
func enableSave () {
if GuestbookContentWordCount >= 3 && addGuestbookNameWordCount >= 2 {
saveAction.isEnabled = true
} else {
saveAction.isEnabled = false
}
}
The ideal situation is when the requirements are met and the user clicks on the "Post" button, I will get the data["name"] and data["content"] and insert it into a database. Right now I have gotten it to work to the point that the "Post" button is enabled after the requirements are met, but when trying to get the data it gives the error "Cannot use instance member 'data' within property initializer; property initializers run before self is available.
Can you please advise how to solve this problem? Thank you.
So this is what I would do
Change your UIAlertAction reference to this outside the viewDidLoad()
var saveAction: UIAlertAction? = nil
Inside the viewDidLoad() you can instantiate it like:
saveAction = UIAlertAction(title:"Post", style: .default, handler: { [weak self] (action) -> Void in
guard let `self` = self else { return }
print(self.data) }
)
[weak self] is used so that you don't end up having retain cycles after your UIViewController is deinitialised.

Swift Initializer for conditional binding must have Optional type, not 'Bool' error with if let statement

So i am coding an app in Xcode and this is a part of the code:
func Signup(_ sender: Any) {
if let email = Email.text != nil, let password =
In the 2nd line i get a error
Initializer for conditional binding must have Optional type, not 'Bool'
Can you help me please?
Obviously, you should eliminate that != nil.
I’d also recommend:
trimming whitespace so someone doesn’t enter space to get past the validation;
use isEmpty of the trimmed string to make sure there’s something there;
start properties and method names with lowercase letters;
I personally give my UITextField properties a TextField suffix (so I can distinguish the emailTextField text field from the email string.
Thus, perhaps something like:
#IBAction func didTapSignup(_ sender: Any) {
guard let email = emailTextField.text?.trimmingCharacters(in: .whitespaces),
!email.isEmpty,
let password = passwordTextField.text?.trimmingCharacters(in: .whitespaces),
!password.isEmpty else {
// tell the user that validation failed here ...
// ... and then return
return
}
// do something with `email` and `password`
}
You might want to check, for example, that the email and password pass some rudimentary rules:
let emailRegexString = "^[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$" // oversimplified email regex
func isAcceptable(email: String, password: String) -> Bool {
let isEmailAcceptable = email.range(of: emailRegexString, options: .regularExpression) != nil
let isPasswordAcceptable = password.count > 4
return isEmailAcceptable && isPasswordAcceptable
}
And then
#IBAction func didTapSignup(_ sender: Any) {
guard let email = emailTextField.text?.trimmingCharacters(in: .whitespaces),
let password = passwordTextField.text?.trimmingCharacters(in: .whitespaces),
isAcceptable(email: email, password: password) else {
// tell the user that validation failed here ...
// ... and then return
return
}
// do something with `email` and `password`
}
Note, that regex is a grossly over-simplified email validation. But you can go nuts on the regex if you really want.
I’d also, at a bare minimum, set up my email and password text fields so that spaces are not allowed. So, specify the delegate for the email and password text fields and then prohibit spaces:
extension ViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return string.rangeOfCharacter(from: .whitespacesAndNewlines) == nil
}
}

App crashing because of no values in the uiTextfield

When I enter a value in the UiTextField and press add button the app works perfectly fine,but when I don't enter a value in the UiTextField, then press the add button the whole app crashes. can someone please help me and show me the light.Thank you in advance and good wishes for you and your family.
This is my code
import UIKit
class ViewController: UIViewController,UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.textFild.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet var textFild: UITextField!
#IBAction func ButtonAwesome(sender: AnyObject) {
let value:Double = Double(textFild.text!)!
let sum:Double = value - 1;
let alert = UIAlertController(title: "km", message: "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementString stringer: String) -> Bool
{
if (textField.text == "" && (stringer == ".")) {
return false;
}
let countdots = textField.text!.componentsSeparatedByString(".").count - 1
if countdots > 0 && stringer == "."
{
return false
}
return true
}
}
A more robust solution would be to use the nil coalescing operator to assert that the initialization of value never fails.
#IBAction func ButtonAwesome(sender: AnyObject) {
let value = Double(textFild.text ?? "0") ?? 0
let sum:Double = value - 1;
let alert = UIAlertController(title: "km", message: "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
This is valid for any of the following "unexpected" values of textField.text: nil, "" (empty) or some character that cannot be used to initialize a Double type variable (e.g. "a"). For all these cases, value is give a value of 0.
As an example, consider the following comparisons between a safe and an un-safe way of solving your initial runtime exception.
We first look at the dangers of forcibly unwrapping optionals - not a safe solution. What if textField.text contains nil or an non-numerical character, e.g. "a"? Result:
var myTextFieldText : String? = nil
/* Example 1: nil value causes runtime error */
if myTextFieldText != "" { // this is 'true' -> enter if closure
let value:Double = Double(myTextFieldText!)!
/* this will fail at run time since we are forcibly (un-safely)
unwrapping an optional containing 'nil' */
}
/* Example 2: non-numeric string character causes runtime error */
myTextFieldText = "a"
if myTextFieldText != "" { // this is 'true' -> enter if closure
let value:Double = Double(myTextFieldText!)!
/* this will fail at run time since we cannot initalize a
Double with a string value "a", hence 'Double(myTextFieldText!)'
returns nil, but since we've appended '!', we, like above,
forcibly tries to unwrap this optional of value nil */
}
You should, generally, always use conditional unwrapping of optionals, to avoid encountering a nil value when forcibly unwrapping optionals, the latter leading to a runtime error.
A more robust version of the example above, making use of the nil coalescing operator:
myTextFieldText = nil
let valueA = Double(myTextFieldText ?? "0") ?? 0 // 0
/* OK, Double(myTextFieldText ?? "0") = Double("0") = 0 */
myTextFieldText = "a"
let valueB = Double(myTextFieldText ?? "0") ?? 0 // 0
/* OK, Double(myTextFieldText ?? "0") = Double("a") = nil (fails)
=> use rhs of outer '??' operator: nil ?? 0 = 0 */
For an alternative method, where you extend UITextField to cover your string to numerical type conversion needs, see Leos neat answer in the following thread:
Swift - Converting String to Int
The thread also contains some other valuable insights w.r.t. reading text as numerical values from UITextField instances.
Finally, when dealing with String to Double value conversion, it might be appropriate to use a fixed precision w.r.t. number of decimal digits in your resulting Double value. For a thorough example of how to do this using NSNumberFormatter and extensions, see:
How to input currency format on a text field (from right to left) using Swift?
Please replace your buttonAwesome method with the following code where you check if textfield is not empty, this will work if textfield has a value:
#IBAction func ButtonAwesome(sender: AnyObject) {
if textFild.text != "" {
let value:Double = Double(textFild.text!)!
let sum:Double = value - 1;
let alert = UIAlertController(title: "km", message: "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
}
Since textfield.text is an optional value and as in your case textfield can or cannot have text. So you should test for optional as give below.
if let textIsAvailable = textfield.text
{
print("Text \(textIsAvailable)")
}
Note : The reason for your crash is you are trying to access value which actually doesn't have any value.

Correct output when .isEmpty != nil but no output in the else statement

This function does print out "Enter a number!" when nothing is entered into the textField but if I DO put something in the textField it still prints out "Enter a number!" I obviously want it to print out "Oh, you're (newAge)" when a number is entered in. What am I missing?
Swift 2.0
#IBAction func SubmitAgeButton(sender: AnyObject) {
let newAge = String(textField.text!)
if ((textField.text?.isEmpty) != nil) {
label.text = "Enter a number!"
}
else {
label.text = "Oh, you're \(newAge)" // This isn't printing out.
return()
}
}
with your code you check if the text is there and returns something at all. Which both "" as well as a non empty string do. namely a Bool.
so if let text = textField.text where !text.isEmpty)

Dynamic Cast Faild - AnyObject to NSArray

I am trying to read textFields values which is coming trough alert controller but I am getting run time error on casting with Anyobject to NSArray
alertUserStatus.addAction(UIAlertAction(title: "Sign Up", style: UIAlertActionStyle.Default, handler: {
alertAction in
//let textField:NSArray=alertUserStatus.textFields as AnyObject! as NSArray
let textField=alertUserStatus.textFields! as AnyObject! as NSArray
let username:String=textField.objectAtIndex(0) as String
let password:String=textField.objectAtIndex(1) as String
var signUpUser=PFUser()
signUpUser.username=username
signUpUser.password=password
signUpUser.signUpInBackgroundWithBlock{
(success:Bool!,error:NSError!)->Void in
if success == true {
println("sign up successfully")
}
else{
println("fail to sign up")
}
}
}))
It always helps to look at the type you are getting from a function before trying to massage it into another type. In this case alertUserStatus.textFields returns [AnyObject]? – that is, an optional array of AnyObject. So there’s really no need to convert it to an AnyObject and then to an NSArray just so you can get the first two entries from it. Instead you want to unwrap it and convert it to an array of String.
It’s also best to avoid using !, even if you’re confident the optional can’t possibly be nil, because one of these days there’ll be an edge case that you miss that doesn’t hold and your code will crash with an inexplicable force-unwrap error message.
// nb you can skip the handler: argument name with trailing-closure syntax
alertUserStatus.addAction(UIAlertAction(title: "Sign Up", style: UIAlertActionStyle.Default) {
alertAction in
if let textFields = alertUserStatus.textFields as? [String] where textFields.count > 1 {
let username = textFields[0]
let password = textFields[1]
// rest of your code...
}
else {
// assert with intelligible message or log error or similar
}
})