I always get this error and I don't know what else to type in.
Do you guys know what's going on?
#IBAction func loginAction(sender: AnyObject)
{
let email = self.emailTextField.text
let password = self.passwordTextField.text
if email != "" && password != ""
{
FIREBASE_REF.authUser(email, password: password, withCompletionBlock: { (error, authData) -> Void in
if error == nil
{
NSUserDefaults.standardUserDefaults().setValue(authData.uid, forKey: "uid")
print("Logged in")
self.logoutButton.hidden = false
self.performSegueWithIdentifier(String, sender: AnyObject?)
self.presentViewController(HomeViewController, animated: true, completion: nil)
}
else
{
print(error)
}
})
}
else
{
let alert = UIAlertController(title: "Error", message: "Enter Email and Password", preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
}
}
#IBAction func logoutAction(sender: AnyObject)
{
CURRENT_USER?.unauth()
NSUserDefaults.standardUserDefaults().setValue(nil, forKey: "uid")
self.logoutButton.hidden = true
}
}
The error is at the line
self.presentViewVontroller(HomeViewController...
I already created a Segue in the storyboard.
if you have created a Segue. firstly select segue and set identifier of Segue.
then perform segue like this
self.performSegueWithIdentifier(identifier, sender: nil)
No need to write this line
self.presentViewController(HomeViewController, animated: true, completion: nil)
Related
Line where error is:
self.passwordField.delegate = self
Code from the button:
#IBAction func unwindToRed(_ sender: Any) {
do {
try Auth.auth().signOut()
let ViewController1 = ViewController()
let ViewNavigationController = UINavigationController(rootViewController: ViewController1)
self.present(ViewNavigationController, animated: true, completion: nil)
} catch let err {
print(err)
}
}
This is the relevant homepage code:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
var userUID: String!
var databaseRef: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
databaseRef = Database.database().reference()
self.passwordField.delegate = self
self.emailField.delegate = self
emailField.attributedPlaceholder = NSAttributedString(string: "Email",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray])
passwordField.attributedPlaceholder = NSAttributedString(string: "Password",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray])
}
override func viewDidAppear(_ animated: Bool) {
if let _ = KeychainWrapper.standard.string(forKey: "uid") {
self.performSegue(withIdentifier: "tohome", sender: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func signInPressed(_ sender: Any) {
Auth.auth().createUser(withEmail: (emailField.text ?? ""), password: (passwordField.text ?? "")) { (user, error) in
if let _eror = error {
//something bad happning
print(_eror.localizedDescription )
let alert = UIAlertController(title: "Error", message: "Invalid Entry or Duplicate.", preferredStyle: UIAlertController.Style.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else{
//user registered successfully
print(user as Any)
if let userID = user?.uid {
KeychainWrapper.standard.set((userID), forKey: "uid")
let databaseRef = Database.database().reference()
databaseRef.child("people").child(userID).child("users").setValue(self.emailField.text!)
databaseRef.child("people").child(userID).child("postID").setValue(userID)
self.performSegue(withIdentifier: "tohome", sender: nil)
}
}
}
}
#IBAction func loginInPressed(_ sender: Any) {
Auth.auth().signIn(withEmail: (emailField.text ?? ""), password: (passwordField.text ?? "")) { (user, error) in
if let _eror = error {
//something bad happning
print(_eror.localizedDescription )
let alert = UIAlertController(title: "Error", message: "Incorrect Email or Password.", preferredStyle: UIAlertController.Style.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else{
//user registered successfully
print(user as Any)
if let userID = user?.uid {
KeychainWrapper.standard.set((userID), forKey: "uid")
self.performSegue(withIdentifier: "tohome", sender: nil) }
}
}
}
Problem is hiding in this line:
#IBAction func unwindToRed(_ sender: Any) {
do {
try Auth.auth().signOut()
let ViewController1 = ViewController() // <-- This is the problem
let ViewNavigationController = UINavigationController(rootViewController: ViewController1)
self.present(ViewNavigationController, animated: true, completion: nil)
} catch let err {
print(err)
}
}
Because you are using storyboards to create your views, you should instantiate your view controller from storyboard. To do this right please refer to Creating View Controllers from Storyboard.
If you're new to iOS development or you don't know why this is required please refer to this post which will explain instantiating view controller from storyboard vs. creating new instance.
My code is as follows:
#IBAction func clicked(_ sender: Any) {
let ref = Database.database().reference()
let pass = password.text
var firpass = ""
var bool = false;
ref.child(name.text as! String).child("password").observeSingleEvent(of: .value, with: { dataSnapshot in
firpass = dataSnapshot.value as? String ?? ""
if firpass == pass {
bool = true
}
if bool {
self.sendname = self.name.text!
let vc = DatabaseTableViewController(nibName: "DatabaseTableViewController", bundle: nil)
vc.finalName = self.sendname
self.navigationController?.pushViewController(vc, animated: true)
self.performSegue(withIdentifier: "username", sender: self)
} else {
let alert = UIAlertController(title: "Error", message: "Incorrect username or password", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
self.performSegue(withIdentifier: "failed", sender: self)
}
})
}
override func shouldPerformSegue(withIdentifier identifier: String?, sender: Any?) -> Bool {
if let ident = identifier {
if ident == "failed" {
return false
}
}
return true
}
When I give the right username and password, I go to the next page, but I get this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<OCRApp.ViewController: 0x105e00f60>) has no segue with identifier 'failed''
*** First throw call stack:
(0x1877aaa48 0x1874d1fa4 0x18b206010 0x104a5b58c 0x104a5ba20 0x104aaa19c 0x104aaa598 0x104a8bb40 0x105cd97fc 0x105cdabd8 0x105ce8c34 0x1877285e4 0x1877235d8 0x187722adc 0x1916a8328 0x18b81dae0 0x104a6cdb0 0x1875ac360)
libc++abi.dylib: terminating with uncaught exception of type NSException
When I give the wrong username/password, I still went to the next page, and I got the above error but with identifier failed instead; when I took out the line self.performSegue(withIdentifier: "failed", sender: self), I still went to the next page and got the message:
Warning: Attempt to present <UIAlertController: 0x102978a00> on <OCRApp.ViewController: 0x10170a650> which is already presenting <OCRApp.DatabaseTableViewController: 0x10206beb0>
What I want is to progress to the next page without errors if you put the correct authentication, and to get just the alert and stay on current page if you give incorrect authentication. How do I do this?
Either use push or performSegue, you cant use both at same time. that will push your view controller twice. I have updated the code below.
#IBAction func clicked(_ sender: Any) {
let ref = Database.database().reference()
let pass = password.text
var firpass = ""
var bool = false;
ref.child(name.text as! String).child("password").observeSingleEvent(of: .value, with: { dataSnapshot in
firpass = dataSnapshot.value as? String ?? ""
if firpass == pass {
bool = true
}
if bool {
self.sendname = self.name.text!
let vc = DatabaseTableViewController(nibName: "DatabaseTableViewController", bundle: nil)
vc.finalName = self.sendname
self.navigationController?.pushViewController(vc, animated: true) // either use push or performSegue, you cant use both.
// self.performSegue(withIdentifier: "username", sender: self)
} else {
let alert = UIAlertController(title: "Error", message: "Incorrect username or password", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil) // if there is an error, you do not need to performSegue.
// self.performSegue(withIdentifier: "failed", sender: self)
}
})
}
We do not have information about your segues, I suggest you instantiate your next ViewController. You can use something like this:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NextViewController") as? NextViewController
present(vc, animated: true, completion: nil)
I am just getting to work with Swift 5 and have to update my apps. I use....
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Home")
self.present(vc, animated: true, completion: nil)
to push users from a sign-in screen to the main app, yet with the updates here's how it looks below (iPhone currently in dark-mode)...
Some questions. What is this functionality definitively called? and how do I go about manipulating it? Say I want to remove it because right now if the user is in the main app they can swipe down and go back to the sign-in screen which would definitely cause problems.
Sign-In View Controller Code
import UIKit
import Firebase
import RealmSwift
class StartViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var email: UITextField!
#IBOutlet weak var password: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Check if user is already logged-in so they don't have to sign-in again
checkUserSignIn()
// Setting textfield delegates so user can press enter and go to next textfield
self.email.delegate = self
self.password.delegate = self
let uid = Auth.auth().currentUser?.uid
print(uid)
print("printing the uid here")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Add a background view to the table view
let backgroundImage = UIImage(named: "startBackground")
let imageView = UIImageView(image: backgroundImage)
self.tableView.backgroundView = imageView
imageView.contentMode = .scaleAspectFill
}
// Check if user is already signed-in, if so push to main app
func checkUserSignIn() {
Auth.auth().addStateDidChangeListener({ (auth, user) in
if (user != nil) {
Database.database().reference().child("users").child((user?.uid)!).observeSingleEvent(of: .value, with: { snapshot in
if snapshot.exists() {
print("user is logged in")
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Home")
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil)
}
})
}
})
}
#IBAction func login(_ sender: Any) {
if self.email.text == "" || self.password.text == "" {
//Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in
let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
Auth.auth().signIn(withEmail: self.email.text!, password: self.password.text!) { (user, error) in
if error == nil {
//Print into the console if successfully logged in
print("You have successfully logged in")
// Proceed To App
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "home") {
} else {
print("Problem sending user into nature app")
}
}
} else {
//Tells the user that there is an error and then gets firebase to tell them the error
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
#IBAction func createAccount(_ sender: Any) {
// Check user has entered text into fields
guard let email = email.text, email != "",
let password = password.text, password != ""
else {
// Throw alert message to user if fields are empty
let alert = UIAlertController(title: "Registration Error", message: "Please make sure you filled in all of the boxes to complete registration!", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
}
// Register a new user on Firebase
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in
// Throw registration error / Account could already exist
if let error = error {
let alert = UIAlertController(title: "Registration Error", message: error.localizedDescription, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
return
}
guard let userID = user?.user.uid else {
return
}
// Database reference
let databaseRef = Database.database().reference()
// Set user information to firebase data structure
let userInfo = fireUsersData(email: email, profPicString: "", uid: userID)
databaseRef.child("users").child(userID).updateChildValues(userInfo.getUserDictionary(), withCompletionBlock: { (err, databaseRef) in
let UserToAdd = realmUserData()
UserToAdd.email = email
UserToAdd.uid = userID
//UserToAdd.saveDataToRealm()
if err != nil {
// Throw error is problem completeting
let alert = UIAlertController(title: "Error", message: (err?.localizedDescription)! as String, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
})
})
// Dismiss keyboard
self.view.endEditing(true)
// Proceed To App
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "home") {
} else {
print("Problem sending user into nature app")
}
}
}
// END OF FILE
}
Before presenting your ViewController give this option:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Home")
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil)
For ignoring dark mode style in didFinishLaunchingWithOptions write this:
if #available(iOS 13.0, *) {
window?.overrideUserInterfaceStyle = .light
}
UPDATE: Replace present to this code:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Home") as! UITabBarController
UIApplication.shared.keyWindow?.rootViewController = vc
Since updating to Swift 3.0 even with the correct password I receive the incorrect message. Has anyone had this problem with authorizing users on Firebase?
#IBAction func LoginToAccount(_ sender: AnyObject) {
if let email = emailLogin.text, let password = passwordLogin.text {
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: {
(user, error) in
if error != nil{
print("Incorrect")
let alert = UIAlertController(title: "Error", message: "Incorrect Email or Password.", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else{
if error == nil {
self.performSegue(withIdentifier: "AdminSegue", sender: self)
}
}
})
}
}
}
If you could create an email and have problem with sign in then it would be like my case. Just check your keychain accessibility from yourproject.xcodeproject -> Capabilities -> keychain Sharing - > On if it is off.
After some research this is apparently an issue with Simulator 10.0 not allowing Firebase to write values to the keychain. Something they are working on apparently but it doesn't affect app on actual device.
You have to make sure the user has been created initially, because you have to create a user first and then sign in using the created user.
#IBAction func LoginToAccount(_ sender: AnyObject) {
if let email = emailLogin.text, let password = passwordLogin.text {
FIRAuth.auth()!.createUser(withEmail: email, password: password) { user, error in
if error == nil {
FIRAuth.auth()!.signIn(withEmail: email, password: password, , completion: { (user, error) in
if error != nil{
print("Incorrect")
let alert = UIAlertController(title: "Error", message: "Incorrect Email or Password.", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
} else {
if error == nil {
self.performSegue(withIdentifier: "AdminSegue", sender: self)
}
}
})
}
}
}
I am using Firebase as a back end and have coded the login part. When I login with a test account the debugger prints "Logged In:. However, when I try to go to the main view controller, I get the error "fatal error: unexpectedly found nil while unwrapping an Optional value" The code breaks on the line self.presentviewcontroller. What am doing wrong here?
if email != "" && password != ""
{
FIREBASE_REF.authUser(email, password: password, withCompletionBlock: {(error, FAuthData) -> Void in
if error == nil
{
NSUserDefaults.standardUserDefaults().setValue(FAuthData.uid, forKey: "uid")
print("logged in")
self.logoutButton.hidden = false
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondViewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
self.presentViewController(secondViewController, animated: true, completion: nil)
}
else{
print("The user was not logged in")
}
})
}
else{
let alert = UIAlertController(title: "ERROR", message: "Please Enter Email and Password", preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
}
Check on your Main Storyboard that you set identifier ViewController to your ViewController.
You'll need to use the observeAuthEventWithBlock method, which listens for the authenticated state in realtime.
override func viewDidAppear() {
let ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com")
ref.observeAuthEventWithBlock({ authData in
if authData != nil {
// user authenticated
print(authData)
self.performSegueWithIdentifier("LoginToOtherView", sender: nil)
} else {
// No user is signed in
}
})
}
You listen is viewDidAppear, so it continues to fire even if you go down the navigation stack.