Show message if all textfields are complete, correctly in swift 4? - ios

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
}

Related

Login Validation from parsed result

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

iOS Swift fetching more data for collection view after having navigated to detail view not working

I am working on an assignment for a job interview. I have finished most of the assignment. There's only a bug i can't figure out. I have been trying for three days now.
I had to make a client app for the Flickr API that allows users to search for photos using specific words. Display the results in a collection view with infinite scroll. And when a photo is selected it should show the details of the photo in a detail view.
The bug:
Everything is working if i stay in the collection view. I can search over and over again and the infinite scroll is also working.As soon as a specific index in the index path is hit. A new request is sent with the same search term. But if i select a photo and then navigate back to the collection view and try a new search nothing comes back and my error handeling returns an error. (the error is not a console error).Also when navigating back from detail to collection. I can still scroll until the index triggers a new request than it also throws an error.
I hope i am explaining it well. I am really getting desperate at the moment. I tried everything i could think of: the request url still works when i try it in the browser.
Please help! If you need more info just ask.
Collection view controller:
import UIKit
// Global variable for holding a search term.
var searchTerm: String?
// Global variable to hold an instance of Reachability.
var reachability: Reachability?
// Enum for changing the textfield placeholder text.
enum TextFieldPlaceHolderText: String {
case Search = "Search"
case Searching = "Searching..."
}
class PhotosViewController: UIViewController {
// MARK: - Outlets
#IBOutlet var collectionView: UICollectionView!
#IBOutlet var searchTextField: UITextField!
// MARK: - Properties
let photoDataSource = PhotoDataSource()
let photoStore = PhotoStore()
// MARK: - View Setup
override func viewDidLoad() {
super.viewDidLoad()
// Sets the data source and delegate.
collectionView.dataSource = photoDataSource
collectionView.delegate = self
// Uses an image to add a pattern to the collection view background.
collectionView.backgroundColor = UIColor(patternImage: UIImage(named: "flickr.png")!)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Checks if the device is connected to the internet.
checkForReachability()
}
// MARK: showAlert
func showAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Cancel, handler: { (nil) in
self.dismissViewControllerAnimated(true, completion: nil)
})
alert.addAction(okAction)
self.presentViewController(alert, animated: true, completion: nil)
}
// MARK: - Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowPhoto" {
if let selectedIndexPath = collectionView.indexPathsForSelectedItems()?.first {
let flickrPhoto = photoDataSource.flickrPhotos[selectedIndexPath.row]
let destinationVC = segue.destinationViewController as! PhotoDetailViewController
destinationVC.flickrPhoto = flickrPhoto
destinationVC.photoStore = photoStore
}
}
}
// MARK: - checkForReachability
func checkForReachability() {
do {
reachability = try Reachability.reachabilityForInternetConnection()
} catch {
print("Unable to create Reachability")
return
}
reachability!.whenReachable = { reachability in
// This is called on a background thread, but UI updates must be on the main thread.
NSOperationQueue.mainQueue().addOperationWithBlock({
if reachability.isReachableViaWiFi() {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
})
}
reachability!.whenUnreachable = { reachability in
// This is called on a background thread, but UI updates must be on the main thread.
NSOperationQueue.mainQueue().addOperationWithBlock({
print("Not reachable")
self.showAlert("No Internet Connection", message: "Make sure your device is connected to the internet.")
})
}
do {
try reachability!.startNotifier()
} catch {
print("Unable to start notifier")
}
}
}
//MARK: - Extension UICollectionViewDelegate
extension PhotosViewController: UICollectionViewDelegate {
//MARK: - willDisplayCell
func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
let flickrPhoto = photoDataSource.flickrPhotos[indexPath.row]
// Downloads the image data for a thumbnail.
photoStore.fetchImageForPhoto(flickrPhoto,thumbnail: true) { (result) -> Void in
// Calls the mainthread to update the UI.
NSOperationQueue.mainQueue().addOperationWithBlock() {
// The indexpath for the photo might have changed between the time the request started and finished, so find the most recent indeaxpath
let photoIndex = self.photoDataSource.flickrPhotos.indexOf(flickrPhoto)!
let photoIndexPath = NSIndexPath(forRow: photoIndex, inSection: 0)
// When the request finishes, only update the cell if it's still visible
if let cell = collectionView.cellForItemAtIndexPath(photoIndexPath) as? PhotoCollectionViewCell {
cell.updateWithImage(flickrPhoto.image)
}
}
}
}
}
//MARK: - Extension UITextFieldDelegate
extension PhotosViewController : UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
// Checks if the textfield is not empty.
if textField.text!.isEmpty {
self.showAlert("S😉rry", message: "No search term detected, please enter a search term.")
return false
}
else {
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
textField.addSubview(activityIndicator)
activityIndicator.frame = textField.bounds
activityIndicator.startAnimating()
textField.placeholder = TextFieldPlaceHolderText.Searching.rawValue
// Sets the text that the user typed as the value for the searchTerm property.
searchTerm = textField.text!
// Fetches the photos from flickr using the user's search term.
photoStore.fetchPhotosForSearchTerm() {
(photosResult) -> Void in
// Calls the mainthread to update the UI.
NSOperationQueue.mainQueue().addOperationWithBlock() {
switch photosResult {
case let .Success(photos):
// Checks if photos were found using the search term.
if photos.count == 0 {
self.showAlert("S😞rry", message: "No images found matching your search for: \(searchTerm!), please try again.")
}
activityIndicator.removeFromSuperview()
textField.placeholder = TextFieldPlaceHolderText.Search.rawValue
// Sets the result to the data source array.
self.photoDataSource.flickrPhotos = photos
print("Successfully found \(photos.count) recent photos.")
case let .Failure(error):
self.checkForReachability()
activityIndicator.removeFromSuperview()
textField.placeholder = TextFieldPlaceHolderText.Search.rawValue
self.photoDataSource.flickrPhotos.removeAll()
self.showAlert("", message: "Something went wrong, please try again.")
print("Error fetching photo's for search term: \(searchTerm!), error: \(error)")
}
self.collectionView.reloadSections(NSIndexSet(index: 0))
}
}
textField.text = nil
textField.resignFirstResponder()
self.collectionView?.backgroundColor = UIColor.whiteColor()
return true
}
}
}
The detail view controller:
import UIKit
import Social
class PhotoDetailViewController: UIViewController {
// MARK: - Outlets
#IBOutlet var photoTitleLabel: UILabel!
#IBOutlet var photoIDLabel: UILabel!
#IBOutlet var dateTakenLabel: UILabel!
#IBOutlet var imageView: UIImageView!
// MARK: Properties
var flickrPhoto: FlickrPhoto!
var photoStore: PhotoStore!
let formatter = FlickrAPI.dateFormatter
// MARK: - View Setup
override func viewDidLoad() {
super.viewDidLoad()
//Downloads the image data for large image
photoStore.fetchImageForPhoto(flickrPhoto, thumbnail: false) { (result) -> Void in
switch result {
case let .Success(image):
// Calls the mainthread to update the UI.
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.imageView.image = image
}
case let .Failure(error):
print(" Error fetching detail image for photo: \(error)")
}
}
// Formats the date a shorte date that doesn't display the time
formatter.dateStyle = .MediumStyle
formatter.timeStyle = .NoStyle
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Checks if the device is connected to the internet.
checkForReachability()
// Configures the UI.
configureView()
}
// MARK: - checkForReachability
func checkForReachability() {
do {
reachability = try Reachability.reachabilityForInternetConnection()
} catch {
print("Unable to create Reachability")
return
}
reachability!.whenReachable = { reachability in
// this is called on a background thread, but UI updates must be on the main thread, like this:
NSOperationQueue.mainQueue().addOperationWithBlock({
if reachability.isReachableViaWiFi() {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
})
}
reachability!.whenUnreachable = { reachability in
// this is called on a background thread, but UI updates must be on the main thread, like this:
NSOperationQueue.mainQueue().addOperationWithBlock({
print("Not reachable")
self.showAlert("No Internet Connection", message: "Make sure your device is connected to the internet.")
})
}
do {
try reachability!.startNotifier()
} catch {
print("Unable to start notifier")
}
}
// MARK: - configureView
func configureView() {
photoTitleLabel.text = flickrPhoto.title ?? "No title available"
photoIDLabel.text = flickrPhoto.photoID ?? "ID unknown"
dateTakenLabel.text = formatter.stringFromDate(flickrPhoto.dateTaken) ?? " Date unknown"
}
// MARK: - showShareOptions
#IBAction func showShareOptions(sender: AnyObject) {
// Configure an action sheet to show the sharing options.
let actionSheet = UIAlertController(title: "Share this photo", message: "", preferredStyle: UIAlertControllerStyle.ActionSheet)
let tweetAction = UIAlertAction(title: "Share on Twitter", style: UIAlertActionStyle.Default) { (action) -> Void in
// Check if sharing to Twitter is possible.
if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
let twitterComposeVC = SLComposeViewController(forServiceType: SLServiceTypeTwitter)
twitterComposeVC.addImage(self.imageView.image)
self.presentViewController(twitterComposeVC, animated: true, completion: nil)
}
else {
self.showAlert("Flickr Searcher", message: "You are not logged in to your Twitter account.")
}
}
// Configure a new action to share on Facebook.
let facebookPostAction = UIAlertAction(title: "Share on Facebook", style: UIAlertActionStyle.Default) { (action) -> Void in
if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
let facebookComposeVC = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
facebookComposeVC.addImage(self.imageView.image)
self.presentViewController(facebookComposeVC, animated: true, completion: nil)
}
else {
self.showAlert("Flickr Searcher", message: "You are not logged in to your facebook account.")
}
}
// Configure a new action to show the UIActivityViewController
let moreAction = UIAlertAction(title: "More", style: UIAlertActionStyle.Default) { (action) -> Void in
let activityViewController = UIActivityViewController(activityItems: [self.imageView.image!], applicationActivities: nil)
self.presentViewController(activityViewController, animated: true, completion: nil)
}
let dismissAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Destructive) { (action) -> Void in
}
actionSheet.addAction(tweetAction)
actionSheet.addAction(facebookPostAction)
actionSheet.addAction(moreAction)
actionSheet.addAction(dismissAction)
presentViewController(actionSheet, animated: true, completion: nil)
}
// MARK: showAlert
func showAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Cancel, handler: { (nil) in
self.dismissViewControllerAnimated(true, completion: nil)
})
alert.addAction(okAction)
self.presentViewController(alert, animated: true, completion: nil)
}
}
My data source:
import UIKit
class PhotoDataSource: NSObject, UICollectionViewDataSource {
//MARK: - Properties
// Array to store the Flickr Photos
var flickrPhotos = [FlickrPhoto]()
// An instance of photoStore.
var photoStore = PhotoStore()
// MARK: - numberOfItemsInSection
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return flickrPhotos.count
}
// MARK: - cellForItemAtIndexPath
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let identifier = "FlickrCell"
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath) as! PhotoCollectionViewCell
let photo = flickrPhotos[indexPath.item]
cell.updateWithImage(photo.image)
print(indexPath.item)
// If you get close to the end of the collection, fetch more photo's.
if indexPath.item == flickrPhotos.count - 20 {
print("Detected the end of the collection")
// Fetch the next batch of photos.
photoStore.fetchPhotosForSearchTerm() {
(photosResult) -> Void in
// Calls the mainthread to update the UI.
NSOperationQueue.mainQueue().addOperationWithBlock() {
switch photosResult {
case let .Success(photos):
print("Successfully found \(photos.count) recent photos.")
self.flickrPhotos.appendContentsOf(photos)
case let .Failure(error):
self.flickrPhotos.removeAll()
print("Error fetching more photos for search term \(error)")
}
collectionView.reloadSections(NSIndexSet(index: 0))
}
}
}
return cell
}
}
This is the method that throws the error. But only when navigated to the detail view first. Staying in the collection view the method gets call over and over with no problem:
photoStore.fetchPhotosForSearchTerm() {
(photosResult) -> Void in
// Calls the mainthread to update the UI.
NSOperationQueue.mainQueue().addOperationWithBlock() {
switch photosResult {
case let .Success(photos):
print("Successfully found \(photos.count) recent photos.")
self.flickrPhotos.appendContentsOf(photos)
case let .Failure(error):
self.flickrPhotos.removeAll()
print("Error fetching more photos for search term \(error)")
}
collectionView.reloadSections(NSIndexSet(index: 0))
}
}

App is performing segue automatically (Swift 2.0, Firebase 3)

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.

Unexpected quirky behavior from socket.io in Swift

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.

Data not updating to current user when new user logs in using Swift and Parse

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

Resources