Parse signup going to next view controller if fields are missing - ios

So I am trying to create a signup page, and I am running into some trouble. I want the user to HAVE to fill in all the information before they hit signup. After they hit the signup button, if they do not have all of the fields filled in they get an UIAlertView error for many different things. When I hit signup, it takes the user to the next page and then displays the UIAlertView, I do not want this to happen. I can't figure out what is happening. If the UIAlertView comes up if they do not have a username or email filled in I need the UIAlertView to display after they click the button and not go to the next page. I have a performSegue method in my code but it is performing first, and not last. Can anybody help me? I will include the screenshot of my storyboard as well.
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? NSString
if fullname.isEmpty || email.isEmpty || username.isEmpty || password.isEmpty {
var emptyFields:UIAlertView = UIAlertView(title: "Plese try again", message: "It looks like you forgot to fill out all the fields. Please make sure all the fields are filled out so we can create an account for you.", delegate: self, cancelButtonTitle: "Try again")
emptyFields.show()
} else if error.code == 203 {
var takenEmail:UIAlertView = UIAlertView(title: "Please try again", message: "It looks like that email has already been taken, please try again.", delegate: self, cancelButtonTitle: "Try again")
} else if error.code == 202 {
var usernameTaken:UIAlertView = UIAlertView(title: "Please try again", message: "It looks like that username is already in use, please try again.", delegate: self, cancelButtonTitle: "Try again")
}
}
}

There are a few ways to do this. The way I would do it is as follows.
Step 1.
Ok you want to select your Sign Up View Controller.
Step 2.
You are going to control click and drag from the Yellow View Controller Icon to the Second View Controller. In the Menu that appears choose the Show Or Present Modally Option.
Step 3.
Choose the Segue you just created and change its Identifier, In the right side panel to "signupSuccessful".
Step 4.
You can set the code up like this.
if usernameTF.text.isEmpty || passwordTF.text.isEmpty {
var emptyFields = UIAlertView()
emptyFields.title = "Plese try again"
emptyFields.message = "It looks like you forgot to fill out all the fields. Please make sure all the fields are filled out so we can create an account for you."
emptyFields.addButtonWithTitle("Try Again!")
emptyFields.show()
}else if usernameTF.text == "ERROR CODE 203" {
//do same thing with the alert view!
}else if usernameTF.text == "ERROR CODE 202" {
//Do another alert view here
//You can keep adding the "else ifs" for any other error codes
}
//Here is where it will send to the second view when everything above is false!
else {
//Here we present the second view.
self.performSegueWithIdentifier("signupSuccessful", sender: self)
}
There you go.
Here is a download of the project if you need to see the segue again, or any of the above code.
https://github.com/bobm77/ParseSegueExample

Implement the method func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool in your view controller and return false if you don't want the segue to happen.

Related

UITest cases to handle with location services alert

I am writing UI test cases for my project.
My project flow is as below:
Login Screen. User enters credentials and press login.
Home Screen. There is location requirement so system as for user's permission. I allow it.
Logout.
So when I do fresh install of application this flow is recorded in test case and works if I perform on new fresh build.
But problem is when I test on old build there is no alert for location permission and the test's gets fail. How can I handle this cases or ask user for permission every time when I run tests?
For resetting credentials of user I am passing launchArguments to XCUIApplication() and handle in AppDelegate.
I have implemented code let me know if its correct way:
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
alert.buttons["Only While Using the App"].tap()
return true
}
The above code works for both if alert comes or not.
Using an interruption monitor is the correct way. However, it's safer to check if the alert being displayed is the alert you're expecting before you interact with the alert:
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
let button = alert.buttons["Only While Using the App"]
if button.exists {
button.tap()
return true // The alert was handled
}
return false // The alert was not handled
}
Try this
let app2 = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let button = app2.alerts.firstMatch.buttons["Allow While Using App"]
button.waitForExistence(timeout: 10)
button.tap()
I use the following code to allow user's location:
// MARK: - Setup
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launch()
addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in
alert.buttons["Allow Once"].tap()
return true
}
}
In this setup, I "register" the interruption monitor for tapping the allow button, so in this case I can dismiss that modal. Now, there's my test:
// MARK: - Test change mall
func testChangeMall() {
let selectorChangeButton = app.buttons["change_mall_button"]
XCTAssert(selectorChangeButton.exists, "Selector change button does not exist")
selectorChangeButton.tap()
app.navigationBars.firstMatch.tap()
let cell = app.staticTexts["Shopping Centre"]
XCTAssert(cell.exists, "There's no cell with this title")
cell.tap()
sleep(1)
let label = app.staticTexts["Shopping Centre"]
XCTAssert(label.exists, "Nothing changes")
}
In this test, simply I go to a view controller with a list sorted by location. First, I need to dismiss the location's system alert. So, first I dismiss that modal and then I tap a cell from my TableView. Then, I need to show it in my main view controller so I dismiss my view controller and I expect the same title.
Happy Coding!

Firebase Database saving data after approvement

I'm using firebase database on an iOS app! I'm writing in swift. I'm using a 'Send' button to write data (ex. textField and label values) on my firebaseDatabase. Is there any way to accept or decline data on my database? What I mean is if a user add something to textfield and press send (which means adding it to my database), I want to accept or decline it to my database, before adding it there!
My button action:
#IBAction func saveBtn(_ sender: Any) {
//Saving item to database
if commentTextField.text != "" && placeLabel.text != "Location"
{
let place = placeLabel.text
let key = dbRef!.child("placeLabel").childByAutoId().key
dbRef!.child(place!+"/placeLabel").child(key).setValue(place)
dbRef!.child(place!+"/comment").child(key).setValue(commentTextField.text)
dbRef!.child(place!+"/rating").child(key).setValue(ratingControl.rating)
commentTextField.text = ""
//alert
createAlert(title: "Thank you!", message: "Review submitted.")
self.navigationController?.popViewController(animated: true)
}else{
//alert
createAlert(title: "Why don't write a review?", message: "Please write a review.")
}
}
If I have understood you currectly, then First way:
1) Add extra field like isAccepted
2) Add new value to your node, but show only if isAccepted == true.
3) If false show some UIView for approving.
Second way:
1) You should create additional node with name like Suggested
actions
2) Let user add to this node
3) Check from your user this node and accept/decline.
4) If accepted - add to final node
Hope it helps
Another way to enable offline capability of firebase database. It will enhance the processing and you don't need to handle this.This will achieve with one line of code only.

How to check whether the user is new user or old user

I have one login screen, which have email, password. And in register screen after user registred they will come to login screen to login.
That time I need to check , if the user is first time user or old user. If first time user means I need to redirect them to my feedback screen. Or old user means I need to redirect them to my home screen. How to do that with firebase?
Her my code for login screen :
#IBAction func loginWithUserNamePassword(){
loginWithMailAndPassword((username.text?.trimWhiteSpace)!, password: (password.text?.trimWhiteSpace)!) { (user, error) in
if error != nil{
KRProgressHUD.dismiss()
SCLAlertView().showError("Login Error", subTitle: error!.localizedDescription)
}
else {
KRProgressHUD.dismiss()
if user!.emailVerified{
currentUser = user
enableSync()
self.callHomescreen()
}
else
{
AlertView().showError("Login Error", subTitle: "This email is has not been verified yet")
}
}
}
}
Or else in my feed back screen there are some text fields. And the model class is :
var feedbackData = [files]()
class files {
// having some string variables
}
By using this, if my data is empty in my feedback screen redirect the user to feedback screen or else redirect them to home screen. Can we do that?
Updated :
if profileData.FirstName.characters.count <= 0 {
print("Home screen calling")
}
else if profileData.FirstName.characters.count > 0 {
print("feedback screen calling")
}
Thought of trying like this. But no use.
If I understand your question currectly, once user is logged in, you want to check the creation date of the use account. To do so you have two options:
The server side. If you are using Firebase database just add the date of creation. Firebase documantation does not offer a method to get the creation date on the app side.
The app side. User user defaults, when the user login in the first time set the date for that user. When you get to the login screen again, check for existance. I would reccomend using the user id as the key.
For example:
Your user just logged in, you want to check if it the first time that he did:
if let displayName = FIRAuth.auth()?.currentUser?.displayName {
//Make sure we have the user
if UserDefaults.standard.bool(forKey: displayName) {
// try to get the user default for the spacific key
let wasConnected = UserDefaults.standard.bool(forKey: displayName)
if wasConnected {
print("This user was connected")
}
} else {
// This user was never connected
// We set the default to his ID
UserDefaults.standard.set(true, forKey: displayName)
UserDefaults.standard.synchronize()
}
}
To use the date, I think the easiest way is to convert the date to string.
Fiddle with the code to do exactly what you want.

NSUserDefaults are not being saved [duplicate]

This question already has answers here:
NSUserDefaults not saving properly
(4 answers)
Closed 7 years ago.
I am having a bear of a time getting my NSUserDefaults to save when the user accepts the license. I'm guessing I am missing something simple but as I have been staring at this for two solid days now, I probably wouldn't see it if it bit me. This is my first project so please understand I am very new to this. Thank you for you patience and assistance.
In the main VC a function runs on ViewDidLoad to determine if the user has accepted the license.
override func viewDidLoad() {
super.viewDidLoad()
print("ViewController.swift View Did Load")
userLicense()
Here is that function:
func userLicense() {
if licenseStatus == nil {
print("nil status - The NSUserDefaults value for lisenceStatus is", licenseStatus)
segueIdentifier = "showEULA"
self.segue()
print("First Run or Not yet accepted or declined. License Status var = ",licenseStatus)
} else {
licenseStatus = NSUserDefaults.standardUserDefaults().objectForKey("licenseStatus")! as? String
print("userLicense func licenseStatus var is ",licenseStatus)
if licenseStatus == "Declined License" {
print("declined status - The NSUserDefaults value for lisenceStatus is", licenseStatus)
segueIdentifier = "showEULA"
segue()
print("Declined License. Send user back to EULA screen")
} else
if licenseStatus == "Accepted License" {
NSUserDefaults.standardUserDefaults().objectForKey("licenseStatus")
print("accepted status - The NSUserDefaults value for lisenceStatus is", licenseStatus,". The app should run.")
//segueIdentifier = "backToLoginScreen"
//segue()
//print("Accepted License")
}
}
}
If the user is not licensed, he is segued to the License Acceptance VC and this code runs:
There is a button to accept the license:
#IBAction func acceptEULA(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setObject("Accepted License", forKey: "licenseStatus")
licenseStatus = NSUserDefaults.standardUserDefaults().objectForKey("licenseStatus")! as! String
print("The Accepted func NSUserDefaults license Status is ", licenseStatus)
segueIdentifier = "backToLoginScreen"
self.passThroughError = "You have chosen to accept the user license. Click cancel to return, otherwise enjoy using MORE 2 Go."
self.passThroughErrorAlertController("Confirm Accept License", error: passThroughError)
}
And a button to Decline the license:
#IBAction func cancelApp(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setObject("Declined License", forKey: "licenseStatus")
licenseStatus = (NSUserDefaults.standardUserDefaults().objectForKey("licenseStatus")! as? String)!
print("The NSUserDefaults licenseStatus is ", self.licenseStatus)
segueIdentifier = "backToLoginScreen"
self.passThroughError = "You have chosen to decine the user license. Click cancel to return, otherwise click OK and the app will be inactive."
self.passThroughErrorAlertController("Confirm Decline License", error: passThroughError)
}
As you see, it is in these button IBActions that I set the licenseStatus var to the appropriate value. The print commands show in the logs that the values are set correctly but when the user is passed back to the login VC, the value has not stuck. Here is the function where the sequel is actually called, in case this is where I am missing a step:
func passThroughErrorAlertController(title:String, error:String) {
let passThroughAlert = UIAlertController(title: title, message: passThroughError, preferredStyle: UIAlertControllerStyle.Alert)
passThroughAlert.addAction((UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)))
passThroughAlert.addAction((UIAlertAction(title: "OK", style: .Default, handler: {action in
print("The user clisked OK, the license status is ", self.licenseStatus)
self.performSegueWithIdentifier(self.segueIdentifier, sender: self)
//self.dismissViewControllerAnimated(true, completion: nil)
})))
self.presentViewController(passThroughAlert, animated: true, completion: nil)
}
I apologize for such a lengthy post but as I said, I have been trying to implement this for two days and none of the references I can find seem to be helping (or I am just missing the forrest for the trees now that I am so far in). Thanks again for your assistance.
You need to synchronize your NSUserDefaults after setting value to it:
NSUserDefaults.standardUserDefaults().synchronize()
or in Objective-C:
[[NSUserDefaults standardUserDefaults] synchronize];
The NSUserDefaults is a file, and settings value to it is writing data to a file - a heavy IO code, so use it only if you need to save some data between app running, and synchronize it after you insert data to it.
If you inseting more than one value, call it at the end, and it will flash all the last inserted data to the file.

iOS 8 and segues throwing unexpected exception

Well I'm coding an app with xcode 6.4 for iOS 8+, I have made a story board and connected several controllers the problem lies when I log out of the app and try to create a new user and go to the menu the app crashes I have an exception break point but I don't really understand why is crashing, any help?
The offending code:
#IBAction func listoTapped(sender: UIButton) {
if usernameRegisterField.text != "" && passwordRegisterField.text != "" {
let user = PFUser()
//2
user.username = usernameRegisterField.text
user.password = passwordRegisterField.text
//3
user.signUpInBackgroundWithBlock { succeeded, error in
if (succeeded) {
//The registration was successful, go to the wall
//self.performSegueWithIdentifier(self.tableViewWallSegue, sender: nil)
self.performSegueWithIdentifier(self.showMenuSegue, sender: self)
//self.dismissViewControllerAnimated(true, completion: nil)
} else if let error = error {
//Something bad has occurred
self.showErrorView(error)
}
}
} else {
var alert: UIAlertController = UIAlertController(title: "Error", message: "Los campos no pueden estar vacios", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
presentViewController(alert, animated: true, completion: nil)
}
}
And the segue crashing:
It only crashes when I log out and then try to register a new user, I'm using a push segue.
EDIT: The solution to the no segues showing, is to enable size classes if you have them off, that will let you choose the show segue.
How do you create the "Login" controller when logging out? Don't you forget to create it with navigation controller to be able to push..
Otherwise please attach some crash information / log
From your diagram, you have a login screen which lets you sign in or add a new user. This screen is the root of a navigation controller.
I assume from the diagram that if you sign in with a know account then it pushes to the main app.
Your new user dialog however is being presented as modal from what I can see. When sign up occurs you then have a show/push segue to the app. However you cannot show/push as there is no navigation controller from this point which is probably your issue.
You could either:
1) Dismiss the signup screen and force a login.
2) Push/Show the signup screen rather than presenting it modally.
If you go for 1), then rather than having to dismiss and hard wire you own data pass back, you could use an unwind segue to pass back the username and password to populate the sign-in screen with the new user details.
In iOS 8, push segue is deprecated. You should use show segue instead.

Resources