How can I show the localized description of an error in an error label format to a user in Swift? - swift

I'm very new to Swift, and Instead of just printing the localized description of an error when a user attempts to register for an app, I want to show it in an error label to the user. However, I get the error "Expression is not assignable: function call returns immutable value." I'm not sure what this means or what I should be doing differently in order to show the default description for the error.
class RegisterViewController: UIViewController {
#IBOutlet weak var emailTextfield: UITextField!
#IBOutlet weak var passwordTextfield: UITextField!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidLoad() {
errorLabel.isHidden = true
}
#IBAction func registerPressed(_ sender: UIButton) {
if let email = emailTextfield.text, let password = passwordTextfield.text {
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.isHidden = false
String(e.localizedDescription) = self.errorLabel.text!
"Expression is not assignable: function call returns immutable value"
} else {
//Navigate to ChatViewController
self.performSegue(withIdentifier: "RegisterToChat", sender: self)
}
}
}
}
}

The assignment must be the other way round. You are going to assign always the right side to the left side.
And you don’t need to create a string from a string
self.errorLabel.text = e.localizedDescription

Related

How to retrieve and show user data from Firebase with swift?

I followed a tutorial to create a register and login screen with firebase and is already working, but now I want to create the screen "My account" with text fields where show the name, mail, etc.. of the user, so my question and I need help is how to get the data from firebase and show that information on that screen, how can I do it please?
I already read the firebase documentation https://firebase.google.com/docs/auth/ios/manage-users but I don't know how to proceed because Im learning programming/swift and I have to still improving my level
I attach the code of the sign up view
import UIKit
import FirebaseAuth
import FirebaseFirestore
import Firebase
class SignUpViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet weak var signUpButton: UIButton!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setUpElements()
}
func setUpElements(){
//Hide the error label
errorLabel.alpha = 0
//Style the elements
Utilities.styleTextField(nameField)
Utilities.styleTextField(lastNameField)
Utilities.styleTextField(emailField)
Utilities.styleTextField(passwordField)
Utilities.styleFilledButton(signUpButton)
}
// Check the fields and validate that the data is correct. If everything is correct, this method returns nil. Otherwise, it returns the error message
func validateFields() -> String? {
// Check that all fields are filled in
if nameField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
lastNameField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
emailField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
passwordField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
return "Please fill in all fields."
}
// Check if the password is secure
let cleanedPassword = passwordField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if Utilities.isPasswordValid(cleanedPassword) == false {
// Password isn't secure enough
return "Please make sure your password is at least 8 characters, contains a special character and a number."
}
return nil
}
#IBAction func signUpTapped(_ sender: Any) {
// Validate the fields
let error = validateFields()
if error != nil {
// There's something wrong with the fields, show error message
showError(error!)
}
else {
// Create cleaned versions of the data
let firstName = nameField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let lastName = lastNameField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let email = emailField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
// Create the user
Auth.auth().createUser(withEmail: email, password: password) { (result, err) in
// Check for errors
if err != nil {
// There was an error creating the user
self.showError("Error creating user")
}
else {
// User was created successfully, now store the first name and last name
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstname":firstName, "lastname":lastName, "uid": result!.user.uid ]) { (error) in
if error != nil {
// Show error message
self.showError("Error saving user data")
}
}
// Transition to the home screen
self.transitionToHome()
}
}
}
}
func showError(_ message:String) {
errorLabel.text = message
errorLabel.alpha = 1
}
func transitionToHome() {
let homeViewController = storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeViewController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
}
And the actual code of my account view controller, just I add it the text fields, I don't know how to proceed
import UIKit
class MyAccountViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var lastnameField: UITextField!
#IBOutlet weak var emailField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
I think that I provided all the info necessary, thank you

Swift 4: Expression implicitly coerced from '[String : String?]' to '[AnyHashable : Any]'

Why I getting an error message in the line that says:
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref)
The error message says:
Expression implicitly coerced from '[String : String?]' to '[AnyHashable : Any]'
What changes could I make to my code to prevent the error message?
Here is all of my code from the view controller:
import UIKit
import Firebase
import FirebaseAuth
class RegisterViewController: UIViewController {
private var ref: DatabaseReference! // референс к БД
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet weak var firstNameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
#IBOutlet weak var cityField: UITextField!
#IBOutlet weak var telNumField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference() // инициализация БД
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func nextButtonPressed(_ sender: Any) {
Auth.auth().createUser(withEmail: self.emailField.text!, password: self.passwordField.text!) { (user, error) in
if error != nil {
print(error!)
self.showAlert(title: "Error!", msg: "Invalid information", actions: nil)
return
}
print("Registration succesfull")
guard let uid = user?.uid else { //доступ к ID пользователя
return
}
self.ref = Database.database().reference() // инициализация БД
let usersReference = self.ref.child("users").child(uid)
let values = ["firstname": self.firstNameField.text, "lastname": self.lastNameField.text, "email": self.emailField.text, "city": self.cityField.text, "telnumber": self.telNumField.text]
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if let err = err {
print(err)
return
}
print("Saved user successfully into Firebase db")
})
}
}
What changes could I make to my code to prevent the error message?
this isn't error where compiler won't let you run your code without fixing it, this is just warning. But message of this warning is important since if you didn't fix it, your string would be saved like this:
Optional("Text from text field")
So, in your case problem is, that you're passing optional property text of type String? as Any which shouldn't be optional.
You can silence this warning and fix your code by force-unwrapping text properties of your text fields (it's safe to force-unwrap it here because, regarding to docs, this property is never nil)
let values = ["firstname": self.firstNameField.text!, "lastname": self.lastNameField.text!, "email": self.emailField.text!, "city": self.cityField.text!, "telnumber": self.telNumField.text!]

Secure text .echosbullets not working for password field

Here's what I've got:
#IBOutlet weak var password: NSSecureTextField!
#IBOutlet weak var shwpswd: NSButton! //Checkbox
#IBOutlet weak var pswdcell: NSSecureTextFieldCell! //Cell
#IBAction func shwpswd(_ sender: Any) {
if(shwpswd.state == 1) {
pswdcell.echosBullets = false // Turn the Secure text into regular text
}
else if(shwpswd.state == 0) {
pswdcell.echosBullets = true // Secure text
}
}
Everything seems to run fine, except the text in the password field doesn't change states between echoing bullets and echoing the real text. Everything is linked together properly too - Cell is within the text field, password button is in the view and the outlet works. I'm wondering if this is another one of the "Swift on mac < Swift on iOS cases".
EDIT: Here is the final solution, should anyone care to see it:
#IBOutlet weak var shwpswd: NSButton! //Checkbox
#IBOutlet weak var visPswd: NSTextfield! //hidden regular box to show chars
#IBOutlet weak var password: NSSecureTextField! //visible initial secure box
#IBAction func shwpswd(_ sender: Any) {
if(shwpswd.state == 1) {
self.visPswd.stringValue = self.password.stringValue //Sync both the text fields
self.password.isHidden = true //hide the secure field
self.visPswd.isHidden = false //show the real character echo field
}
else if(shwpswd.state == 0) {
self.password.stringValue = self.visPswd.stringValue //Sync the two
self.password.isHidden = false // Inverse of above
self.visPswd.isHidden = true
}
}
Note the text fields password and visPswd are the same size and position in the view - one remains hidden at all times to avoid overlapping. When the user enters values in either the password or visPswd field, it syncs with the other field when the checkbox state is changed.
You can accomplish what you want adding a second text field in top of your secure field. Add an IBAction to your check box to switch your fields isHidden property and copy the other textField stringValue and make it the first responder. Your implementation should look like something like this:
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var password: NSSecureTextField!
#IBOutlet weak var showPassword: NSTextField!
#IBOutlet weak var shwpswd: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
shwpswd.state = .off
showPassword.isHidden = true
}
override func viewDidAppear() {
super.viewDidAppear()
password.window?.makeFirstResponder(password)
}
#IBAction func showHidePassword(_ sender: NSButton) {
showPassword.isHidden.toggle()
password.isHidden.toggle()
if !showPassword.isHidden {
showPassword.stringValue = password.stringValue
showPassword.becomeFirstResponder()
} else {
password.stringValue = showPassword.stringValue
password.becomeFirstResponder()
}
}
}
show/hide password sample

Despite multiple unwrapping attempts, fatal error: unexpectedly found nil while unwrapping an Optional value

I have been practicing a login page and the creation of an account with Firebase. I am successfully signing up a user and saving the user in firebase. Now I am trying to save a first and last name to the user id when they create their account. I've tried looking at other SO answers, but still can't seem to get this to work.
I have been going through multiple tutorials, and have tried multiple unwrapping attempts, but keep running into this error. Below is my view controller:
View Controller
import UIKit
import Firebase
class ViewController: UIViewController {
var ref: DatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var firstNameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
var ref = Database.database().reference()
}
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text, let firstName = firstNameField.text, let lastName = lastNameField.text {
Auth.auth().createUser(withEmail: email, password: password ) { (user, error) in
// ...
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
//add popup later
}
let userId = user!.uid
self.ref.child("users").child(userId).setValue(["firstName": firstName])
print("User registered in Firebase with a userId of " + user!.uid)
}
}
}
Where am I going wrong? I thought I was unwrapping the variables at the top, with my 'if let'. I tried force unwrapping them individually, as well, but keep having the same error. A bit lost.
in viewDidLoad(), you call
var ref = Database.database().reference()
but it should be
ref = Database.database().reference()
Swift is treating it like a different variable that you're declaring within the scope of viewDidLoad(), so when you go to use ref, it still has no value.
Please change your Database reference from
var ref: DatabaseReference!
to
var databaseRef = Database.database().reference()
and then do
self.child("users").child(userId).setValue(["firstName": firstName])
or in you viewDidLoad do
self.ref = Database.database().reference()
This error happens because you are not initialising your Database reference
This should work without any problems
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController {
var ref: DatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var firstNameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
}
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text, let firstName = firstNameField.text, let lastName = lastNameField.text {
Auth.auth().createUser(withEmail: email, password: password ) { (user, error) in
// ...
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
//add popup later
}
let userId = user!.uid
self.ref.child("users").child(userId).setValue(["firstName": firstName])
print("User registered in Firebase with a userId of " + user!.uid)
}
}
}

Saving UITextView Text to Parse

I was wondering how to save the text inside UITextView to parse. Everytime I run my code below an error comes up saying it accidentally "found nil when unwrapping an optional" on the lines that save the information to parse.
Note: The functions "SaveNotesParse" and "SaveFrontScreenInfo" are where the errors occur. They are also both called in another class.
#IBOutlet weak var titleText: UITextView!
#IBOutlet weak var descriptionText: UITextView!
#IBOutlet weak var titleText2: UITextView!
#IBOutlet weak var contentText: UITextView!
let testObject = PFObject(className: "Notes")
func SaveNotesParse () {
//parse stuff
testObject["Title2"] = titleText2.text
testObject["Content"] = contentText.text
print("Saving")
testObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
print("Object has been saved.")
}
}
func SaveFrontScreenInfo () {
testObject["Title"] = titleText.text
testObject["Description"] = descriptionText.text
}
override func awakeFromNib() {
foregroundView.layer.cornerRadius = 10
foregroundView.layer.masksToBounds = true
super.awakeFromNib()
}
override func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
let durations = [0.26, 0.2, 0.2]
return durations[itemIndex]
}
Image of the error and line that it appears:
Line that the error message appears
The actual error message as shown in the logs
Try using the setObject function like so:
testObject.setObject(titleText2.text, forKey: "Title2")
Otherwise, can you tell us what is nil? It will have to be either the testObject or the Text Fields. Try printing them to see which one is nil.