Swift Expected Expression in list of Expression Error - ios

Im making a basic registration form, and I'm getting multiple "Expected Expression in list of Expression Errors," as well as a couple expected separator errors. Ive tried fixing the errors myself, but I'm new at Swift, and wasn't able to fix it. Any help is appreciated.
import UIKit
class RegisterPageViewController: UIViewController {
#IBOutlet weak var userFullNameTextField: UITextField!
#IBOutlet weak var userEmailTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
#IBOutlet weak var userRepeatPasswordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func RegisterButtonTapped(sender: AnyObject) {
let userFullName = userFullNameTextField.text
let userEmail = userEmailTextField.text
let userPassword = userPasswordTextField.text
let userRepeatPassword = userRepeatPasswordTextField.text
}
// Check for empty fields
**//ERROR HERE EXPECTED DECLARATION**
if (((userFullName.isEmpty || userEmail.isEmpty || userPassword.isEmpty || userRepeatPassword.isEmpty))
{
// Display alert message
displayMyAlertMessage("All fields are required")
return;
}
// Check if passwords match
if(userPassword != userRepeatPassword)
{
// Display alert message
displayMyAlertMessage("Passwords do not match")
return;
}
func displayAlertMessage(userMessage:string)
{
var myAlert = UIAlertController(title:"Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert);
}
}
// Store Data
// Display alert message with confirmation
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

Error 1: Non-closed parantheses
You're missing a closing paranthesis in the first if statement of the RegisterButtonTapped function:
if (((userFullName!.isEmpty || userEmail!.isEmpty
|| userPassword!.isEmpty || userRepeatPassword.isEmpty)) {
// Display alert message
displayMyAlertMessage("All fields are required")
return
}
Three left pranthesis ((( finished by only two right ones )). I this case, you really need no set of parantheses at all, but could save one set for readability:
if (userFullName!.isEmpty || userEmail!.isEmpty
|| userPassword!.isEmpty || userRepeatPassword.isEmpty) {
// Display alert message
displayMyAlertMessage("All fields are required")
return
}
Error 2: trying to include a function declaration within another function
(As pointed out by Duy Tran)
The function displayAlertMessage(...) is positioned within the function RegisterButtonTapped. Functions may only exists as methods directly in a class/structure etc (or as a global non-class owned function e.g. in a playground).
Hence, you should make sure the function displayAlertMessage(...) is placed outside the body of function RegisterButtonTapped.
General remarks
You should avoid "forced unwrappings" of optional variables. E.g. userFullName!.isEmpty will lead to a runtime exception in case the optional immutable userFullName has valuenil`. You should read up on optionals, optional binding, and so on.
Also note that you needn't put semi-colons ; after lines in Swift. However you won't get an error for doing so:
[swift-evolution] Proposal to remove semicolons

The function displayAlertMessage is placed within the IBAction body.
It should be placed outside your IBAction function.

Related

Why does my UITextfField seems to be NOT nil, even if I leave the field empty? My "else" part of the if-statment is not being read

I am practicing swift programing by making an app that holds customers' data. The app has several text fields where people are supposed to type their name, email address, phone number, and quantity of products purchased. Then with a 'submit' button they save that information into the data base. However, if one of the fields is empty, an error should be thrown and a message should appear to the user letting him/her know that one of the fields empty.
The problem is that even if the textfield is empty, the compiler is not reading it as nil, so my condition is not working.
For simplicity, I am omitting a lot of code. I will only work with one UITextField (customer's name), and my condition will check if the TextField is empty or not. If empty, it should print "Please enter a valid name." if it is NOT nil, it should print the customer's name.
class RaffleViewControler: UIViewController, UITextFieldDelegate {
#IBOutlet weak var customerNameTextField: UITextField!
#IBAction func addCustomerName(_ sender: UITextField) {
}
#IBOutlet weak var submitButton: UIButton!
#IBAction func submitCustomer(_ sender: UIButton) {
if let name = customerNameTextField.text {
print(name)
} else {
print("Please enter a valid name")
}
}
Alternatively, I was also checking my condition in the following format:
#IBAction func submitCustomer(_ sender: UIButton) {
if customerNameTextField.text != nil {
print("Congrats. Your data is in our database")
} else {
print("Please enter a valid name")
}
}
The problem:
Even if I leave the textfield empty, the compiler does not read the "else" part of the condition. Which seems to indicate that the field is never nil. What could be happening?
According to the Apple docs:
This string is #"" by default.
I.e. it is not nil by default.
To check empty UITextField your can use simply
txtFieldName.text?.isEmpty
this will give you BOOL value.
You can simply check:
if self.customerNameTextField.text == "" {
// An empty text field.
} else {
// Not empty.
}

Referencing IBOutlet in another View Controller

So, I have been having some major trouble figuring this out and I have searched extensively for a solution but I surprisingly could not find one. I am attempting to create a multiple page (5, to be exact) Sign-Up for users.
I'll start off by showing you the layout of page 1 and 5 (since solving that issue will solve the issue for page 2-4):
Sign Up Page #1
Sign Up Page #5
As you may see (from the page control dots), I am using a page view controller to allow users to scroll from page to page. What I am trying to accomplish is giving the user the ability to enter their sign-up information in pages 1-5 before submitting it all at once (which can be located on page 5).
Here is the current code I am using for page #1:
class SignUpInfoViewController: UIViewController {
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is the current code I am using for page #5:
class TermsOfUseViewController: UIViewController {
let minPasswordCharCount = 6
#IBAction func signUpAction(_ sender: Any) {
let providedEmailAddress = SignUpInfoViewController().emailTextField.text!
let providedPassword = SignUpInfoViewController().passwordTextField.text!
let trimmedPassword = providedPassword.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if !(validEmail(enteredEmail: providedEmailAddress) && validPassword(enteredPassword: trimmedPassword)) {
invalidCredentialsAlert()
}
else {
FIRAuth.auth()?.createUser(withEmail: providedEmailAddress, password: providedPassword) { user, error in
if error == nil {
FIRAuth.auth()!.signIn(withEmail: providedEmailAddress,
password: providedPassword)
}
else {
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
// Email is valid if it has a standard email format
func validEmail(enteredEmail: String) -> Bool {
let emailFormat = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %#", emailFormat)
return emailPredicate.evaluate(with: enteredEmail)
}
// Password is valid if it is not empty or greater than a specified number of characters
func validPassword(enteredPassword: String) -> Bool {
if (enteredPassword != "" && enteredPassword.characters.count >= minPasswordCharCount) {
return true
}
return false
}
In the TermsOfUseViewController class, I am attempting to use the emailTextField and passwordTextField outlets from the SignUpInfoViewController, but I am receiving the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
I debugged the error and saw that the emailTextField property from SignUpInfoViewController is nil and so force unwrapping it will cause the app to crash (Note: I have correctly connected the IBOutlets to the SignUpInfoViewController, so no issue there).
How can I safely transfer the usage of the IBOutlets from the SignUpInfoViewController class to the TermsOfUseViewController class without it crashing? In other words, how can I make it to where the IBOutlets are no longer nil when I reference them in the TermsOfUseViewController class?
Thank you!
That is a perfect scenario for delegate pattern
protocol SignUpProtocol: class {
func didProvideUserData(username: String ,password: String)
}
In your signup class declare a delegate: public weak var delegate:SignUpProtocol?
I am assuming when the user has provided the require info, they need to press some button to go to the next step: Thus in that button you should raise the delegate
#IBAction func nextButton(sender:UIButton) {
guard let username = usernameTextfield?.text, let password = passwordTextField?.text, else { fatalError("textfields were empty") }
if delegate != nil { // this saying when someone is listening to me, I will expose any method associated to me
delegate?.didProvideUserData(username:username, password:password) // passing the username and password from textfield
}
}
if you don't have a button, then look at property observer, where you could have some property
var didFulfill:Bool? = nil {
didSet {
if didFulfill != nil && didFulfill == true {}
// here you check if your textfields are sets then raise the delegate
}
}
set this property didFulfill = when both textfields are not empty :)
Now in your Terms class, just subscribe to that delegate
class TermsOfUseViewController: UIViewController, SignUpProtocol {
var signUpVc: SignUpInfoViewController?
override func viewDidLoad() {
super.viewDidLoad()
signUpVc = SignUpInfoViewController()
signUpVc?.delegate = self
}
func didProvideUserData(username: String, password:String) {
// there is your data
}
}
You have to take in account that you don't have all references for all UIPageViewControllers all the time. That being said, I would suggest either to keep object in UIPageViewController with updated information or using Singleton Pattern to use it to store info into it and later use it. UIPageViewController are being reused and you might have one before and one after and relying onto having them would be wrong.
You can use UIPageViewController as self.parentViewController or something like that.

Getting input from text field in ViewController and using in another class

In ViewController.swift, I have a text field whose input I would like to use and manipulate in my other class, Conjugate.swift. I am capturing the input at the same time the keyboard is hidden, like so:
import UIKit
class MainViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var mainTextField: UITextField!
var input: String!
override func viewDidLoad() {
super.viewDidLoad()
mainTextField.delegate = self
}
/* KEYBOARD HIDE */
func textFieldShouldReturn(textField: UITextField) -> Bool {
input = self.mainTextField.text
textField.resignFirstResponder()
return true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
And then in my other class:
class Conjugate {
var infinitive: String!
var isEndingAr = false
func conjugate() {
// gets verb from text field
infinitive = MainViewController().input
// checks verb ending and sets value to booleans
if (infinitive.hasSuffix("ar")) {
isEndingAr = true
}
}
}
Here is the error I'm getting:
fatal error: unexpectedly found nil while unwrapping an Optional value
I know that input in MainViewController.swift is still nil. I just don't know why. What am I doing wrong?
When you do infinitive = MainViewController().input, MainViewController() just creates a new instance of MainViewController. That new instance never calls textFieldShouldReturn and therefore its input will be nil. Instead, add a reference from Conjugate to MainViewController.
var mainViewController: MainViewController?
Then in textFieldShouldReturn create a Conjugate and assign its property:
let conjugate = Conjugate()
conjugate.mainViewController = self
Then in the conjugate() method, instead of creating a new view controller, refer to the property:
func conjugate() {
// gets verb from text field
infinitive = self.mainViewController!.input!
// checks verb ending and sets value to booleans
if (infinitive.hasSuffix("ar")) {
isEndingAr = true
}
}
}
Also, like #emresancaktar said, input should be optional, since it might be nil. However, infinitive does not have to be optional.

Use of unresolved identifier when creating a string

I am very new to swift, but i can work with javascript and php so thought this would make sense to me. I have read so many posts on this topic but non really explain mine. I have the following code which is pretty straight forward. I have several text fields with login information to pass on to php. But when i try to use the var from a function it is not possible. So i figured that out but when i try to redefine the vars outside of the function with different var i am still keep getting the error. This is the code so far
import UIKit
class RegisterPage: UIViewController, UITextFieldDelegate{
#IBOutlet weak var userEmailTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
#IBOutlet weak var userPasswordConfirmTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func registerTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text
let userPassword = userPasswordTextField.text
let userConfirmPassword = userPasswordConfirmTextField.text
// check for empty fields
if(userEmail.isEmpty || userPassword.isEmpty || userConfirmPassword.isEmpty)
{
// Display alert message
displayMyAlertMessage("Alle velden gelieve invullen");
return;
}
//Check if passwords match
if(userPassword != userConfirmPassword){
// Display alert message
displayMyAlertMessage("Wachtwoorden komen niet overeen");
return;
}
}// end of registerTapped button
// send data to server side
static var urlConn: NSURL = NSURL(string: "http://xxxxxxxxx")!
var request: NSMutableURLRequest = NSMutableURLRequest(URL:urlConn);
var credLogin = "email=\(userEmail)&password=\(userPassword)"
the following line is giving the unresolved identifier error
var credLogin = "email=\(userEmail)&password=\(userPassword)"
i have tried so many different things, but i can't move the var in the function outside of it, and i have had also in other code blocks errors like this, i really would like to know how this works in swift.
Thanks
The variables userEmail and userPassword are declared within the scope of the registerTapped method. They are not visible outside this method.
Either put the line
var credLogin = "email=\(userEmail)&password=\(userPassword)"
in the method or declare the variables as instance variables right after IBOutlet declarations.
The code to send data to server side must be also executed within a method.

How to call a function from a different function?

I'm trying to make a simple app that counts the characters of a textfield, but when the user inputs the text, the function that converts the user-inputed string into a var and the function that counts the characters are executed at once. Here's the code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var myTextField : UITextField
#IBOutlet var userTextField : UITextField
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTextField.text = fullConstant
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func modifyMyVariable(sender : AnyObject) {
myVariable = userTextField.text
}
#IBAction func clickMe(sender : AnyObject) {
countCharacters(&fullConstant)
println(fullConstant)
myTextField.text = fullConstant
}
}
And here's the "OtherFile.swift" where the functions are located:
import Foundation
var fullConstant = "Type something!"
var myVariable = ""
func modifyMyVariable() {
println()
}
func countCharacters(inout fullConstant: String) {
let FirstPart = "There are "
let LastPart = " characters"
var numberOfCharacters = countElements(myVariable)
switch numberOfCharacters {
case 0 :
fullConstant = "There isn't any character yet"
case 1 :
fullConstant = "There is just one character"
default :
fullConstant = FirstPart + String(numberOfCharacters) + LastPart
}
}
Both functions execute as soon the userTextField is edited, but if the user inputs one character, the countCharacters function takes the var myVariable before it's modified by the function modifyMyvariable, so it doesn't count the last character added.
To solve this, I've thought that I could call the function countCharacters from the function modifyMyVariable, so the variable myVariable has already changed when it counts the characters.
Change the following and see if it's then easier to fix your problem.
You should always only link each event to one IBAction. Your IBActions shouldn't be named after what you're trying to do in them; they should be named after the event that triggers them. For example, "modifyMyVariable" should be called "textEdited" or similar.
In that "textEdited" method, do all the work you need to do. If you need to call another function, call it from there instead of linking to two IBActions.
Put code in your "OtherFile" inside a
class OtherFile {
}
block, and hold an instance to that class as a variable in your view controller. You want to avoid declaring global functions outside of classes.
Not related, but name your constants using camelCase with first letter lower case, just like your variables. So FirstPart should be firstPart.
Avoid using 'inout' as much as possible. Each language has it's conventions; in ObjC and Swift, pass in values needed to do work, and return values that result from that work. So:
func countCharacters(text: String) -> (String)
Putting it all together, your 'modifyMyVariable' function (which should really be called 'textEdited') will look something like this:
myVariable = userTextField.text
let characterCount = self.myOtherFileInstance.countCharacters(myVariable)
myTextField.text = characterCount
and the other function (clickMe) should be deleted.

Resources