I've successfully parsed an result from a SOAP WebServices request I made, by sending in a userName and password.
But now I need to validate this login function and if true segue to a new view programmatically:
let menuPageView = (self.storyboard?.instantiateViewController(withIdentifier: "MenuCentral"))!
self.present(menuPageView, animated: true, completion: nil)
The problem is I don't know how or where to add such validation.
class LoginCentralViewController: UIViewController, SOAPServiceProtocol {
var chave = ChaveWebService().chave()
var soapService : SOAPService?
var resultadoLoginCentral : [LoginCentralModel]!
#IBOutlet weak var txtUsuarioOUTLET: UITextField!
#IBOutlet weak var txtSenhaOUTLET: UITextField!
#IBOutlet weak var btnAcessarOUTLET: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
soapService = SOAPService(delegate: self)
print(chave)
}
#IBAction func btnAcessarACTION(_ sender: Any) {
soapService?.loginCentral(userName: txtUsuarioOUTLET.text!, password: txtSenhaOUTLET.text!, methodName: nomeServico)
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didSuccessRequest(results: XMLIndexer, requestName: String) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
switch requestName {
case nomeServico:
do{
resultadoLoginCentral = try LoginCentralModel.realizarLoginCentral(results: results)
} catch let error as XMLParseError{
print(error.description)
return
} catch {
print(error)
return
}
print("codigoCliente = ", resultadoLoginCentral[0].codigoCliente)
print("permissoes = " , resultadoLoginCentral[0].permissoes)
break
default:
break
}
}
func didFailRequest(err: String, requestName: String) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
switch requestName {
case nomeServico:
return
default:
break
}
}
func showAlert() {
let loginAlert = UIAlertController(title: "Central do Assinante", message: "Login/Senha inválidos", preferredStyle: .alert)
let acaoDefault = UIAlertAction(title: "OK", style: .destructive, handler: nil)
loginAlert.addAction(acaoDefault)
present(loginAlert, animated: true, completion: nil)
}
}
You can put your validation code here
do{
resultadoLoginCentral = try LoginCentralModel.realizarLoginCentral(results: results)
//Put here code
// we need to call this in main thread
DispatchQueue.main.sync {
if resultadoLoginCentral.codigoCliente.characters.count > 0 && resultadoLoginCentral.permissoes.characters.count > 0{{
// Login process
}else{
//Show Alert
}
}
}
Hope this helps
Related
I am creating a email input and a name input, and I need to show a message when all fields are complete. But for some reason, when empty fields are there and the user clicks on the submit button, the success message shows instead. Is there way to put in a clause or something to fire it after all fields are completed? thanks for the help.
Here is my code:
import UIKit
import MessageUI
class RequestFilterVC: UIViewController {
#IBOutlet weak var emailTxtField: UITextField!
#IBOutlet weak var filterTxtField: UITextField!
#IBOutlet weak var requestBtn: UIButton!
#IBOutlet weak var validatorMessage: UILabel!
#IBOutlet weak var requestedMessage: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// hide validator message
validatorMessage.isHidden = true
requestedMessage.isHidden = true
}
#IBAction func requestBtnWasTapped(_ sender: Any) {
let providedEmailAddress = emailTxtField.text
let isEmailAddressValid = isValidEmailAddress(emailAddressString: providedEmailAddress!)
if isEmailAddressValid
{
print("Email address is valid")
} else {
print("Email address is not valid")
displayAlertMessage(messageToDisplay: "Email address is not valid")
}
// If All are completed then send the email .
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self as? MFMailComposeViewControllerDelegate
// Configure the fields of the interface.
composeVC.setToRecipients(["myemail#awesomeemail.com])
composeVC.setSubject("Form Submit)
composeVC.setMessageBody("\(emailTxtField, filterTxtField)", isHTML: false)
// Present the view controller modally
// self.present(composeVC, animated: true, completion: nil)
requestedMessage.isHidden = false
requestedMessage.text = "Submitted form . thank you"
}
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
}
func displayAlertMessage(messageToDisplay: String)
{
let alertController = UIAlertController(title: "Error", message: messageToDisplay, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default) { (action:UIAlertAction!) in
print("Ok button tapped");
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion:nil)
}
}
You are not checking if the second text field is empty or not anywhere. ( I have no clue why you have named a text field that is supposed to store a name is named as filterTextField )
if isEmailAddressValid && !filterTextField.text?.isEmpty {
print("Email address is valid")
} else {
print("Email address is not valid")
displayAlertMessage(messageToDisplay: "Email address is not valid")
return
}
How does it sound create a delegate with a regex? each time you press a key call the delegate and if it matches the regex you could unhide a UILabel... something like this could work.
Change
displayAlertMessage(messageToDisplay: "Email address is not valid")
To
displayAlertMessage(messageToDisplay: "Email address is not valid")
return
For your problem the following change will handle the error
After you validate the email you are not returning or braking the flow and it will execute the remaining coed left in your function. So you need to stop the execution.
if isEmailAddressValid
{
print("Email address is valid")
} else {
print("Email address is not valid")
displayAlertMessage(messageToDisplay: "Email address is not valid")
}
How ever for better approach, I would suggest to disable the submit
button until the text field has value.
func textFieldDidBeginEditing(textField: UITextField!) { //delegate method
//check for the required text field
if (emailTxtField.text!.isEmpty){
//disable submit button
}
else{
// enable the submit button
}
}
func textFieldShouldEndEditing(textField: UITextField!) -> Bool { //delegate method
if (emailTxtField.text!.isEmpty){
//disable submit button
}
else{
// enable the submit button
}
return true
}
The app crashes when I perform the segue. I checked if there was any sigbrt errors, but there was not. I think it is firebase analytics from the log. This error was from the log :
terminating with uncaught exception of type NSException.
The code
#IBOutlet weak var email: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var adduser: UIButton!
#IBOutlet weak var errormessege: UILabel!
var databaseref = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
password.isSecureTextEntry = true
adduser.isEnabled = false
}
#IBAction func didtapcancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func didtapadd(_ sender: Any) {
adduser.isEnabled = false
FIRAuth.auth()?.createUser(withEmail: email.text!, password: password.text!, completion: {(user,error) in
if error != nil {
if error!._code == 17999 {
self.errormessege.text = "Invalid email address" }
else {
self.errormessege.text = error?.localizedDescription
}
}
else
{
FIRAuth.auth()?.signIn(withEmail: self.email.text!, password: self.password.text!, completion: {(user,error) in
if (error == nil) {
self.databaseref.child("users").child(user!.uid).child("email").setValue(self.email.text!)
self.performSegue(withIdentifier: "hi", sender: nil)
}
else {
self.errormessege.text = error?.localizedDescription
}
})
}
}
)
}
#IBAction func didtextchange(_ sender: Any) {
if((email.text?.characters.count)!>0){
adduser.isEnabled = true}
else{
adduser.isEnabled = false}
}
#IBAction func did4(_ sender: Any) {
if((password.text?.characters.count)!>0){
adduser.isEnabled = true}
else{
adduser.isEnabled = false}
}
Without more code and the entire scenario in front of me it is hard to specifically nail down what is happening between your code and Firebase. One thing that will significantly help you though in tracking down this error is to validate the data you are pulling out of your #IBOutlets each steps of the way. That way your program is not force unwrapping these objects and leaving opening up your code to risk.
#IBOutlet weak var email: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var adduser: UIButton!
#IBOutlet weak var errormessege: UILabel!
var databaseref = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
password.isSecureTextEntry = true
adduser.isEnabled = false
}
#IBAction func didtapcancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func didtapadd(_ sender: Any) {
adduser.isEnabled = false
guard let emailText = email.text,
let passwordText = password.text else {
// Handle error safely
print("Error unrapping email text or password text")
return
}
FIRAuth.auth()?.createUser(withEmail: emailText, password: passwordText, completion: { (user,error) in
if error != nil {
if error!._code == 17999 {
self.errormessege.text = "Invalid email address"
} else {
self.errormessege.text = error?.localizedDescription
}
} else {
FIRAuth.auth()?.signIn(withEmail: emailText, password: passwordText, completion: { (user, error) in
if (error == nil) {
guard let uid = user.uid else {
// handle error safely
print("Error with user uid")
return
}
self.databaseref.child("users").child(uid).child("email").setValue(emailText)
self.performSegue(withIdentifier: "hi", sender: nil)
}
else {
self.errormessege.text = error?.localizedDescription
}
})
}
})
}
#IBAction func didtextchange(_ sender: Any) {
guard let emailText = email.text else {
// Return error safely
print("Error unrapping email text")
return
}
if emailText.characters.count> 0 {
adduser.isEnabled = true
} else{
adduser.isEnabled = false
}
}
Been smashing my face against the wall all day trying to upgrade my app to the Firebase 3.x code.
I was having a ton of trouble with updating my original userAuth code and decided to just start from scratch. I haven't really been able to test it though because when I run the app it is calling the segue immediately upon loading the initial VC. Obviously I don't want it to do this and I don't know what is causing it.
I've tried deleting the app from the simulator and when I load it back up I get the same result.
Here is my code for the VC:
import UIKit
import FirebaseAuth
class SignInViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
override func viewDidAppear(animated: Bool) {
if let user = FIRAuth.auth()?.currentUser {
self.signedIn(user)
}
}
#IBAction func didTapSignIn(sender: AnyObject) {
// Sign In with credentials.
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.signInWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(user!)
}
}
#IBAction func didTapSignUp(sender: AnyObject) {
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.createUserWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.setDisplayName(user!)
}
}
func setDisplayName(user: FIRUser) {
let changeRequest = user.profileChangeRequest()
changeRequest.displayName = user.email!.componentsSeparatedByString("#")[0]
changeRequest.commitChangesWithCompletion(){ (error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(FIRAuth.auth()?.currentUser)
}
}
#IBAction func didRequestPasswordReset(sender: AnyObject) {
let prompt = UIAlertController.init(title: nil, message: "Email:", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.Default) { (action) in
let userInput = prompt.textFields![0].text
if (userInput!.isEmpty) {
return
}
FIRAuth.auth()?.sendPasswordResetWithEmail(userInput!) { (error) in
if let error = error {
print(error.localizedDescription)
return
}
}
}
prompt.addTextFieldWithConfigurationHandler(nil)
prompt.addAction(okAction)
presentViewController(prompt, animated: true, completion: nil);
}
func signedIn(user: FIRUser?) {
MeasurementHelper.sendLoginEvent()
AppState.sharedInstance.displayName = user?.displayName ?? user?.email
AppState.sharedInstance.photoUrl = user?.photoURL
AppState.sharedInstance.signedIn = true
NSNotificationCenter.defaultCenter().postNotificationName(Constants.NotificationKeys.SignedIn, object: nil, userInfo: nil)
performSegueWithIdentifier(Constants.Segues.SignInToFp, sender: nil)
}
}
Can someone please help? Thank you in advance.
As per title, I'm having some trouble dealing with socket.io. It connects really well and accordingly in the first view controller but weird things happen when it comes to second controller.
Here's the code:
First Controller: I have declared some global variable for connection purposes between both view controller.
import UIKit
import SocketIOClientSwift
import SwiftyJSON
import CoreData
//declare some global variable
var patientCoreData = [NSManagedObject]()
var numberOfUsersExisting:Int = 0 //assign to 0 by default
var appUserData: Patient? //for specific user
var pSample: Array<Patient> = [] //for all user
//initiate socket globally
let socket = SocketIOClient(socketURL: "localhost:3000", options: [
"reconnects": true
])
func reportStatus(){
socket.on("connect") {data, ack in
print("Report status: View Controller connected")
socket.emit("click", "Client app connected")
}
}
func readDataFromSocket(completion: (data:AnyObject)-> ()){
socket.on("reply") {data, ack in
print("database replied")
completion(data: data)
}//socket
}//readDataFromSOCKET
func importData(){
reportStatus()
socket.connect()
readDataFromSocket(){ data in
let json = JSON(data)
let nou = json[0].count
if nou > 0 {
print("Test(1st VC): grabbing data from database")
for var i=0; i<nou; ++i{
numberOfUsersExisting = nou
pSample += [Patient(id: json[0][i]["ID"].intValue, name: json[0][i]["Name"].stringValue, gender: json[0][i]["Gender"].stringValue, mileage: json[0][i]["Mileage"].doubleValue)]
pSample.sortInPlace({$0.globalPatientMileAge < $1.globalPatientMileAge})
}
print("Successfully grabbed data")
}else{
print("No user in the database")
numberOfUsersExisting = 0
}
}//readDataFromSocket
}
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
print("First view appeared")
let prefs = NSUserDefaults.standardUserDefaults()
//if an user has logged in
let isLoggedIn = prefs.integerForKey("ISLOGGEDIN") as Int
if (isLoggedIn != 1){
print("No user currently, so heading to login screen")
socket.disconnect()
self.performSegueWithIdentifier("gotoLogin", sender: self)
}else{
print("ViewDidAppear: An user has been logged in")
let permissionToLoadData = prefs.integerForKey("ISLOGGEDIN")
if (permissionToLoadData != 1) {
print("Please grant permission to get data")
}else{
print("First view: connecting to database")
importData()
}//permission to load data
}
}//end of viewDidAppear
}
Second Controller:
import UIKit
import SocketIOClientSwift
import SwiftyJSON
import CoreData
var nou:Int?
class LoginViewController: UIViewController {
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
let registeredUserID = NSUserDefaults.standardUserDefaults().stringForKey("registerPatientID")
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
func displayAlertMessage(userMessage:String){
let alert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)
alert.addAction(okAction)
self.presentViewController(alert, animated: true, completion: nil)
}
func successMessage(userMessage:String){
let alert = UIAlertController(title: "Welcome Back", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)
alert.addAction(okAction)
self.presentViewController(alert, animated: true, completion: nil)
}
#IBOutlet weak var loginPatientID: UITextField!
#IBAction func LoginButton(sender: AnyObject) {
let logInUserID = loginPatientID.text
if (logInUserID!.isEmpty){
displayAlertMessage("Please enter your Patient ID!")
return
}else{
print("Test: requesting login permission from database")
socket.emit("loginRequest", logInUserID!)
print("Test: requested")
socket.on("loginReply") {data, ack in
let jsonLogin = JSON(data)
if jsonLogin[0].intValue == 1{
print("Test: ID Matched, putting up ViewController")
self.prefs.setObject(logInUserID, forKey: "AppUserID")
self.prefs.setInteger(1, forKey: "ISLOGGEDIN")
self.prefs.synchronize()
let permissionToLoadData = self.prefs.integerForKey("ISLOGGEDIN")
if (permissionToLoadData != 1) {
print("Please grant permission to get data")
}else{
print("First view: connecting to database")
importData()
print("Did you import?")
}//permission to load data
self.loginPatientID.resignFirstResponder()
self.dismissViewControllerAnimated(true, completion: nil)
}else if jsonLogin[0].intValue == 0{
self.displayAlertMessage("Sorry, you are not assigned to this program")
}else if jsonLogin[0].intValue == 3{
print("Test: Query problem")
}else{
print("Test: not getting anything from ID database")
}
}//socket.on
}//else
}//login button
override func viewDidLoad() {
super.viewDidLoad()
print("Login View Controller loaded")
}
override func viewDidAppear(animated: Bool) {
socket.connect()
print("LoginVC: establishing connection")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You may have noticed that in First view controller, when the viewDidAppear() is launched, the app will checks if user is login or not. If somebody has already logged in, it's fine. If there is nobody logging in, it will perform a segue(modally segue) to Second view controller.
A login form will be presented in second view controller and once user hits the login button, you might wanna look at the code.
Let's assume that everything goes right until it comes to importData(), the function isn't launched at all but the app just goes on, why?
Here's a screenshot of the console, pay attention to "Did you import?", if the function is launched, the app should return some additional message from 1st view controller.
After struggling for a few days, I think I may have found the correct answer.
Eventually I defined 2 different socket handlers connection as such:
let loginSocket = SocketIOClient(socketURL: "localhost:3000")
let socket = SocketIOClient(socketURL: "localhost:3000", options: [
"reconnects": true
])
for both view controller.
If there is a conclusion I can draw from this conundrum is that we can't use single socket handler for socket methods from different view controller.
Im working on an app that uses phone number and SMS verification to login. It all works well except for one small issue. If I logout of one user, then login with another, the previous users data is loaded, however a new user is created but the previous users data is displayed. I have to logout and login the new user again to load their data. Anybody see whats going on?
Login code:
class LoginViewController: UIViewController {
func displayAlert(title: String, message: String) {
var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (action) -> Void in
}))
self.presentViewController(alert, animated: true, completion: nil)
}
#IBOutlet weak var instructionLabel: UILabel!
#IBOutlet weak var phoneNumberTextField: UITextField!
#IBOutlet weak var sendCodeButton: UIButton!
var phoneNumber: String = ""
override func viewDidLoad() {
super.viewDidLoad()
first()
self.editing = true
}
func first() {
phoneNumber = ""
phoneNumberTextField.placeholder = "555-555-5555"
instructionLabel.text = "Enter your phone number to login or sign up"
sendCodeButton.enabled = true
}
func second() {
phoneNumber = phoneNumberTextField.text!
phoneNumberTextField.text = ""
phoneNumberTextField.placeholder = "1234"
instructionLabel.text = "Enter your 4 digit security code"
sendCodeButton.enabled = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
phoneNumberTextField.becomeFirstResponder()
}
#IBAction func didTapSendCodeButton() {
let preferredLanguage = NSBundle.mainBundle().preferredLocalizations[0]
let textFieldText = phoneNumberTextField.text ?? ""
if phoneNumber == "" {
if (preferredLanguage == "en" && textFieldText.characters.count != 10) {
displayAlert("Phone Login", message: NSLocalizedString("warningphone", comment: "You must enter a 10 digit US phone number including area code"))
return first()
}
self.editing = false
let params = ["phoneNumber" : textFieldText, "language" : preferredLanguage]
PFCloud.callFunctionInBackground("sendCode", withParameters: params) { response, error in
self.editing = true
if let error = error {
var description = error.description
if description.characters.count == 0 {
description = NSLocalizedString("warningGeneral", comment: "Something went Wrong. Please try again")
} else if let message = error.userInfo["error"] as? String {
description = message
}
self.displayAlert("Login Error", message: description)
return self.first()
}
return self.second()
}
} else {
if textFieldText.characters.count == 4, let code = Int(textFieldText) {
return doLogin(phoneNumber, code: code)
}
displayAlert("Code Entry", message: NSLocalizedString("warningCodeLength", comment: "You must enter the 4 digit code texted to your number"))
}
}
func doLogin(phoneNumber: String, code: Int) {
self.editing = false
let params = ["phoneNumber": phoneNumber, "codeEntry": code] as [NSObject:AnyObject]
PFCloud.callFunctionInBackground("logIn", withParameters: params) { response, error in
if let description = error?.description {
self.editing = true
return self.displayAlert("Login Error", message: description)
}
if let token = response as? String {
PFUser.becomeInBackground(token) { user, error in
if let _ = error{
self.displayAlert("Login Error", message: NSLocalizedString("warningGeneral", comment: "Something happened while logging in. Please try again"))
self.editing = true
return self.first()
}
return self.dismissViewControllerAnimated(true, completion: nil)
}
} else {
self.editing = true
self.displayAlert("Login Error", message: NSLocalizedString("warningGeneral", comment: "Something went wrong. Please try again"))
return self.first()
}
}
}
override func setEditing(editing: Bool, animated: Bool) {
sendCodeButton.enabled = editing
phoneNumberTextField.enabled = editing
if editing {
phoneNumberTextField.becomeFirstResponder()
}
}
}
extension LoginViewController : UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.didTapSendCodeButton()
return true
}
}
Found the problem I had to update the label in viewWillAppear