Error: Argument passed to call that takes no arguments - ios

I'm creating a simple login signup app. But I'm getting an error, and I don't know how to fix it, please help! Here's my code:
//
// ViewController.swift
// CHLogbook-Application
//
// Created by Timothy Dillan on 06/01/18.
// Copyright © 2018 TPINC. All rights reserved.
//
import UIKit
import FirebaseAuth
import Firebase
class ViewController: UIViewController {
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password, completion: { user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
self.presentLoggedInScreen()
})
}
}
#IBAction func loginTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
self.presentLoggedInScreen()
})
}
}
func presentLoggedInScreen() {
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loggedInVC:LoggedInVC = storyboard.instantiateInitialViewController(withIdentifier:"LoggedInVC") as! LoggedInVC
self.present(loggedInVC, animated: true, completion: nil)
}
}
The error is in this line in the withIdentifier part, which, when I wanted to run it, always says "Argument passed to call that takes no arguments":
let loggedInVC:LoggedInVC = storyboard.instantiateInitialViewController(withIdentifier:"LoggedInVC") as! LoggedInVC

instantiateInitialViewController takes no arguments, it simply initializes the first view controller of the storyboard. You are looking for instantiateViewController.
let loggedInVC = storyboard.instantiateViewController(withIdentifier:"LoggedInVC") as! LoggedInVC

Do not use this Code
func presentLoggedInScreen() {
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loggedInVC:LoggedInVC = storyboard.instantiateInitialViewController(withIdentifier:"LoggedInVC") as! LoggedInVC
self.present(loggedInVC, animated: true, completion: nil)
}
Look Up first line. You instantiate new Main.Storyboard which takes memory. Use storyboard which already in memory.
func presentLoggedInScreen() {
let loggedInVC = storyboard?.instantiateInitialViewController(withIdentifier:"LoggedInVC") as! LoggedInVC
self.present(loggedInVC, animated: true, completion: nil)
}

Related

Passing data from viewcontroler to tab viewed controllers in swift

I have this login form:
import UIKit
class LoginViewController: UIViewController {
var user : LoginUser?
#IBAction func btnLoginPressed(_ sender: Any) {
if self.textFieldLogin.text?.isEmpty ?? true || self.textFieldPassword.text?.isEmpty ?? true {
self.errorLoginMessage(txt: "Error", title: "Error")
} else {
let cms = ServerConnect()
cms.checkUsersLogin(login: self.textFieldLogin.text, password: self.textFieldPassword.text, completion: { (data) in
switch(data) {
case .succes(let data):
var actionToRun: ()-> Void
let decoder = JSONDecoder()
self.user = try? decoder.decode(LoginUser.self, from: data)
dump(self.user)
// we have an user
if ((self.user?.id ) != nil) {
actionToRun = {
self.performSegue(withIdentifier: "toLoginUser", sender: self)
}
}
// we have an error
else if let json = try? JSONSerialization.jsonObject(with: data, options: []),
let dictionary = json as? [String: Any],
let message = dictionary["komunikat"] as? String,
let title = dictionary["error"] as? String {
// we have an error
actionToRun = {
self.errorLoginMessage(txt: message, title: title)
}
}
// default error
else {
actionToRun = {
self.errorLoginMessage(txt: "Podany login lub hasło jest błędny!!", title: "Błąd")
}
}
DispatchQueue.main.async {
actionToRun()
}
case .error(let error):
print("Error 104: \(error)")
}
})
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "toLoginUser" {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabVC = storyboard.instantiateViewController(withIdentifier: "MainVC") as! UITabBarController
self.present(tabVC, animated: true, completion: {
let vc = tabVC.selectedViewController as! NewsViewController
vc.loggedUser = self.user
})
}
}
func errorLoginMessage(txt: String, title: String){
let alertController = UIAlertController(title: title, message: txt, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: { (action: UIAlertAction!) in
}))
self.present(alertController, animated: true, completion: nil)
}
}
The object is built correctly.
I would like to pass my object from the login view to tab viewed controllers.
I am receiving the object like this:
class NewsViewController: UIViewController {
var loggedUser : LoginUser?
override func viewDidLoad() {
super.viewDidLoad()
print("check object: \(loggedUser)")
dump(loggedUser)
}
#IBAction func testBtnPressed(_ sender: Any) {
print("check object: \(loggedUser)")
dump(loggedUser)
}
}
Unfortunately this code does not work and I always get nil.
My full source code: https://bitbucket.org/trifek/karta-nauka/src/master/
Can I ask for help?
It is not good idea to pass info view controller to view controller which is used by almost all of your view controller's
Like Login information which contains info that is nearly used by all of the screen
Good idea is to create Global Shared class which will store your all global information which is shared among the application.
public final class AppGlobalManager {
static let sharedManager = AppGlobalManager()
var loggedUser : LoginUser?
}
Now whenever user login you can
AppGlobalManager.sharedManager.loggedUser = object
And when user logout
AppGlobalManager.sharedManager.loggedUser = nil
Hope it is helpful
If you are already using segues in the storyboard, you don't have to get the desired view controller from the UIStoryboard, the segues itself provides the destination view controller.
Example:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toLoginUser" {
let tabVC = segue.destination as! UITabBarController
// assuming that `NewsViewController` is the first view controller in the tabbar controller:
let destinationViewController = tabVC.viewControllers?[0] as! NewsViewController
destinationViewController.loggedUser = self.user
}
}
Since you are aiming to pass the LoginUser object to one of the tabbar view controllers, you could get it from the tabbar viewControllers array -as mentioned in the code snippet above-.

Can't present login screen before tabbarcontroller

I have code for multiple screens in my application. I'm trying to add in a TabBarController for the app once a user has logged in, however now the application is ignoring the login view controller. Here's my code for my login screen:
import UIKit
import CoreML
import Vision
import FirebaseAuth
class ViewController: UIViewController {
#IBOutlet weak var emailTextfield: UITextField!
#IBOutlet weak var passwordTextfield: UITextField!
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextfield.text, let password = passwordTextfield.text {
Auth.auth().createUser(withEmail: email, password: password, completion: { user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
self.presentVisRecogScreen()
})
}
}
#IBAction func loginTapped(_ sender: Any) {
if let email = emailTextfield.text, let password = passwordTextfield.text {
Auth.auth().signIn(withEmail: email, password: password, completion: {(user, error) in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
self.presentVisRecogScreen()
})
}
}
func presentVisRecogScreen(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier :"myTabBar")
self.present(viewController, animated: true)
}
}
It was my understanding that the application would present this screen, and once the presentVisRecogScreen function was called it would then show the Tabbed application. Where am I going wrong?
I found the issue, which I'm sure is a blatant newbie error. I hadn't ticked the box to say that my login screen was the Initial View Controller.
Works perfectly now.

how to keep a user login even if they close the app? I'm using swift 3, and Firebase

I'm new to coding and to Stack overflow, I'm trying to have a user stay logged in even after they close the app. I also don't want them to always see the login in screen. how do I do i go about keeping the user Login even if they close the app and re-open the app. I'm using Swift 3.0, Xcode 8, and Firebase.
import UIKit
import Firebase
import SwiftKeychainWrapper
class LoginViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var pwField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(LoginViewController.dismissKeyboard))
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
//tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
// Do any additional setup after loading the view.
}
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
#IBAction func loginPressed(_ sender: Any) {
guard emailField.text != "", pwField.text != "" else {return}
FIRAuth.auth()?.signIn(withEmail: emailField.text!, password: pwField.text!, completion: { (user, error) in
if let error = error {
print(error.localizedDescription)
}
if user != nil {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TabBarViewController")
self.present(vc, animated: true, completion: nil)
}
})
}
}
Below is my UsersViewController code it has the log-out button
import UIKit
import Firebase
class UsersViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
var user = [User]()
override func viewDidLoad() {
super.viewDidLoad()
retrieveUsers()
}
func retrieveUsers() {
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let users = snapshot.value as! [String : AnyObject]
self.user.removeAll()
for (_, value) in users {
if let uid = value["uid"] as? String {
if uid != FIRAuth.auth()!.currentUser!.uid {
let userToShow = User()
if let fullName = value["full name"] as? String, let imagePath = value["urlToImage"] as? String {
userToShow.fullName = fullName
userToShow.imagePath = imagePath
userToShow.userID = uid
self.user.append(userToShow)
}
}
}
}
self.tableview.reloadData()
})
ref.removeAllObservers()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! UserCell
cell.nameLabel.text = self.user[indexPath.row].fullName
cell.userID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
checkFollowing(indexPath: indexPath)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return user.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let uid = FIRAuth.auth()!.currentUser!.uid
let ref = FIRDatabase.database().reference()
let key = ref.child("users").childByAutoId().key
var isFollower = false
ref.child("users").child(uid).child("following").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
if let following = snapshot.value as? [String : AnyObject] {
for (ke, value) in following {
if value as! String == self.user[indexPath.row].userID {
isFollower = true
ref.child("users").child(uid).child("following/\(ke)").removeValue()
ref.child("users").child(self.user[indexPath.row].userID).child("followers/\(ke)").removeValue()
self.tableview.cellForRow(at: indexPath)?.accessoryType = .none
}
}
}
if !isFollower {
let following = ["following/\(key)" : self.user[indexPath.row].userID]
let followers = ["followers/\(key)" : uid]
ref.child("users").child(uid).updateChildValues(following as Any as! [AnyHashable : Any])
ref.child("users").child(self.user[indexPath.row].userID).updateChildValues(followers)
self.tableview.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
})
ref.removeAllObservers()
}
func checkFollowing(indexPath: IndexPath) {
let uid = FIRAuth.auth()!.currentUser!.uid
let ref = FIRDatabase.database().reference()
ref.child("users").child(uid).child("following").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
if let following = snapshot.value as? [String : AnyObject] {
for (_, value) in following {
if value as! String == self.user[indexPath.row].userID {
self.tableview.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
}
}
})
ref.removeAllObservers()
}
#IBAction func logOutPressed(_ sender: Any) {
do {
try FIRAuth.auth()?.signOut()
if FIRAuth.auth()?.currentUser == nil {
// Remove User Session from device
UserDefaults.standard.removeObject(forKey: "uid")
UserDefaults.standard.synchronize()
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginVC") as! LoginViewController
}
} catch let signOutError as NSError {
// handle logout error
}
}
}
extension UIImageView {
func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}
}
Firebase Auth can handle this for you. Like with Firebase Database, Auth works by setting up listeners. You can listen for an existing user in your App Delegate like so:
final class AppDelegate: UIResponder, UIApplicationDelegate {
private let auth = FIRAuth.auth()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
auth?.addStateDidChangeListener { [weak self] (_, user) in
if let user = user {
// user is already logged in
} else {
// user is not logged in
}
}
}
}
When the user is successfully logged in, put their UID in UserDefaults to store the session like so:
UserDefaults.standard.set(FIRAuth.auth()!.currentUser!.uid, forKey: "user_uid_key")
UserDefaults.standard.synchronize()
Then, whatever is the first View Controller that your apps loads, check for that key in the viewDidAppear() like this:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Check if the user is logged in
if UserDefaults.standard.object(forKey: "user_uid_key") != nil {
// send them to a new view controller or do whatever you want
}
}
Put the UserDefaults in the success block of the IBAction/Function where you register/login your user like shown below:
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if user != nil {
// Login success
// Saves User UID to UserDefaults
UserDefaults.standard.set(FIRAuth.auth()!.currentUser!.uid, forKey: "USER_KEY_UID")
UserDefaults.standard.synchronize()
}
else {
// login error
})
Remove the UserDefault when the user logs out:
#IBAction func logoutButtonPressed(sender: UIButton!) {
do {
try FIRAuth.auth()?.signOut()
if FIRAuth.auth()?.currentUser == nil {
// Remove User Session from device
UserDefaults.standard.removeObject(forKey: "USER_KEY_UID")
UserDefaults.standard.synchronize()
let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
present("TheVCYouWantToSendTheUserTo", animated: true, completion: nil)
}
} catch let signOutError as NSError {
// handle logout error
}
}
UPDATED:
You forgot to include UserDefaults in your Login func. This is why it gives you an error. Add this to you login IBAction.
#IBAction func loginPressed(_ sender: Any) {
guard emailField.text != "", pwField.text != "" else {return}
FIRAuth.auth()?.signIn(withEmail: emailField.text!, password: pwField.text!, completion: { (user, error) in
if let error = error {
print(error.localizedDescription)
// You forgot to save User UID to UserDefaults here...
UserDefaults.standard.set(FIRAuth.auth()!.currentUser!.uid, forKey: "uid")
UserDefaults.standard.synchronize()
}
if user != nil {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TabBarViewController")
self.present(vc, animated: true, completion: nil)
}
})
}

Trouble with switching views if users email and password are correct

Was wondering if anyone could help me out. I just finished my Sign Up page where the user can create an account. The problem I have now is that in the Login View the user can simply just press the Login button and it will redirect them to the next view even if their email and password are incorrect.
class LoginViewController: UIViewController, GIDSignInUIDelegate {
#IBOutlet var userEmailLoginField: UITextField!
#IBOutlet var userPasswordLoginField: UITextField!
#IBAction func loginButton(_: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController
guard let email = userEmailLoginField.text, let password = userPasswordLoginField.text else { return }
FIRAuth.auth()?.signIn(withEmail: email, password: password) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
}
}
Try moving your code that instantiates the new view controller. In the example below I moved it to only run if there is no error when authenticating with Firebase.
class LoginViewController: UIViewController, GIDSignInUIDelegate {
#IBOutlet var userEmailLoginField: UITextField!
#IBOutlet var userPasswordLoginField: UITextField!
#IBAction func loginButton(_: Any) {
guard let email = userEmailLoginField.text, let password = userPasswordLoginField.text else { return }
FIRAuth.auth()?.signIn(withEmail: email, password: password) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController
}
}
}

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.

Resources