kaabo7227
@kaabo7227 (kazuki mochinaga)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Firebaseを用いたユーザーログイン機能のエラーについて

解決したいこと

Firebaseを用いたemailとpasswordでのログイン認証アプリを作成中です。
現在アカウントの作成はできるのですが、
既存のアカウントを使用したログインが下記エラーで止まってしまうためできません
ググって調べても情報もあまりなく、解決方法を教えていただきたいです。
よろしくお願い致します。

発生している問題・エラー

@main の行で下記のエラーが出ている。
Thread 1: "-[youtubeLoginApp.LoginViewController tappedRegisterButton:]: unrecognized selector sent to instance 0x7fb2a8d32070"

出ているエラーメッセージを入力

tapped Login Button
2021-07-29 21:26:59.557052+0900 youtubeLoginApp[14321:374339] -[youtubeLoginApp.LoginViewController tappedRegisterButton:]: unrecognized selector sent to instance 0x7fd80257df30
2021-07-29 21:26:59.564312+0900 youtubeLoginApp[14321:374339] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[youtubeLoginApp.LoginViewController tappedRegisterButton:]: unrecognized selector sent to instance 0x7fd80257df30'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff20422fba __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff20193ff5 objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff20431d2f +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
    3   UIKitCore                           0x00007fff246f60f1 -[UIResponder doesNotRecognizeSelector:] + 292
    4   CoreFoundation                      0x00007fff204274cf ___forwarding___ + 1455
    5   CoreFoundation                      0x00007fff204297a8 _CF_forwarding_prep_0 + 120
    6   UIKitCore                           0x00007fff246c7937 -[UIApplication sendAction:to:from:forEvent:] + 83
    7   UIKitCore                           0x00007fff23fe845d -[UIControl sendAction:to:forEvent:] + 223
    8   UIKitCore                           0x00007fff23fe8780 -[UIControl _sendActionsForEvents:withEvent:] + 332
    9   UIKitCore                           0x00007fff23fe707f -[UIControl touchesEnded:withEvent:] + 500
    10  UIKitCore                           0x00007fff24703d01 -[UIWindow _sendTouchesForEvent:] + 1287
    11  UIKitCore                           0x00007fff24705b8c -[UIWindow sendEvent:] + 4792
    12  UIKitCore                           0x00007fff246dfc89 -[UIApplication sendEvent:] + 596
    13  UIKitCore                           0x00007fff247727ba __processEventQueue + 17124
    14  UIKitCore                           0x00007fff24768560 __eventFetcherSourceCallback + 104
    15  CoreFoundation                      0x00007fff20390ede __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    16  CoreFoundation                      0x00007fff20390dd6 __CFRunLoopDoSource0 + 180
    17  CoreFoundation                      0x00007fff2039029e __CFRunLoopDoSources0 + 242
    18  CoreFoundation                      0x00007fff2038a9f7 __CFRunLoopRun + 875
    19  CoreFoundation                      0x00007fff2038a1a7 CFRunLoopRunSpecific + 567
    20  GraphicsServices                    0x00007fff2b874d85 GSEventRunModal + 139
    21  UIKitCore                           0x00007fff246c14df -[UIApplication _run] + 912
    22  UIKitCore                           0x00007fff246c639c UIApplicationMain + 101
    23  libswiftUIKit.dylib                 0x00007fff53fcbf42 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
    24  youtubeLoginApp                     0x000000010bf4e30a $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 122
    25  youtubeLoginApp                     0x000000010bf4e27e $s15youtubeLoginApp0C8DelegateC5$mainyyFZ + 46
    26  youtubeLoginApp                     0x000000010bf4e3a9 main + 41
    27  libdyld.dylib                       0x00007fff2025abbd start + 1
)
libc++abi: terminating with uncaught exception of type NSException
terminating with uncaught exception of type NSException
CoreSimulator 757.5 - Device: iPhone 11 (00FF170C-32E4-41F3-9FEA-D5E2323AA02F) - Runtime: iOS 14.5 (18E182) - DeviceType: iPhone 11
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[youtubeLoginApp.LoginViewController tappedRegisterButton:]: unrecognized selector sent to instance 0x7fd80257df30'

〜動作流れ〜
1.Xcodeでシュミレータでアプリを起動 (下記画像参照)
2.ログインをタップして画面を遷移
3.すでに登録してあるemailとpasswordを入力する
4.ログインをタップする
5.ログイン完了できず、エラーで止まってしまう。

【問題・エラーが起きている画像】
スクリーンショット 2021-07-29 21.44.43.png
スクリーンショット 2021-07-29 21.43.39.png
スクリーンショット 2021-07-29 21.42.52.png

該当するソースコード

AppDelegate.swift
import UIKit
import Firebase

@main
class AppDelegate: UIResponder, UIApplicationDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        FirebaseApp.configure()

        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}
ViewController.swift

import UIKit
import Firebase
import PKHUD

struct User {

    // 構造の変数定義はFireBaseから取得したデータ(変数:data)と同じ変数を使用すること
    let name: String
    let createdAt: Timestamp
    let email: String


    init(dic: [String: Any]) {
        self.name = dic["name"] as! String
        self.createdAt = dic["createdAt"] as! Timestamp
        self.email = dic["email"] as! String
    }
}

class ViewController: UIViewController {

    @IBOutlet weak var registerButton: UIButton!
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var usernameTextField: UITextField!

    @IBAction func tappedRegisterButton(_ sender: Any){
        handleAuthToFirebase() // ???
        print("登録ボタンを押したよ!")
}


    @IBAction func tappedHaveAccountButton(_ sender: Any) {
        let storyBoard = UIStoryboard(name: "Login", bundle: nil) // name: "Home" のところはエラーがでたので name: "Main" に変えた
        let homeViewController = storyBoard.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
        navigationController?.pushViewController(homeViewController, animated: true)
//        self.present(homeViewController, animated: true, completion: nil)
    }



    private func handleAuthToFirebase(){
        HUD.show(.progress, onView: view)
        guard let email = emailTextField.text else {return}
        guard let password = passwordTextField.text else {return}

        Auth.auth().createUser(withEmail: email, password: password) { (res, err) in
            if let err = err {
                print("認証情報の保存に失敗しました。\(err)") // "\(err)"はエスケープシーケンス -> 詳しくは"memo.swift"で

                HUD.hide{ (_) in
                    HUD.flash(.error, delay: 1)
                }

                return
            }
            print("認証情報の保存に成功しました!")
            self.addUserInfoToFirestore(email: email)
        }
    }

    private func addUserInfoToFirestore(email: String){
        guard let uid = Auth.auth().currentUser?.uid else { return }
        guard let name = self.usernameTextField.text else { return }

        let docData = ["email": email, "name": name, "createdAt":Timestamp()] as [String : Any]
        let userRef = Firestore.firestore().collection("users").document(uid)

        userRef.setData(docData) { (err) in // HP "FireBase"内で作成したデータベースのコレクション=colection ("users") = users
            if let err = err {
                print("FireBaseStoreの保存に失敗しました。\(err)") // "\(err)"はエスケープシーケンス -> 詳しくは"memo.swift"で

                HUD.hide{ (_) in
                    HUD.flash(.success, delay: 1)
                }

                return
            }
            print("FireStoreの保存に成功しました!")


            userRef.getDocument{ (snapshot, err) in // firebaseからデータを引っ張ってくる処理
                if let err = err {
                    print("ユーザー情報の取得に失敗しました。 \(err)")

                    HUD.hide{ (_) in
                        HUD.flash(.error, delay: 1)
                    }

                    return
                }

                guard let data = snapshot?.data() else { return }
                let user = User.init(dic: data)


                print("ユーザー情報の取得に成功しました。\(user.name)")

                HUD.hide{ (_) in
//                    HUD.flash(.success, delay: 1)
                    HUD.flash(.success, onView: self.view, delay: 1) { (_) in
                        self.presentToHomeViewController(user: user)
                    }
                }

// "present" の引数について
// 第一引数: 遷移先のUIViewController
// 第二引数: アニメーションの指定(true: アニメーション有 / false: アニメーション無)
//  第三引数: コールバック関数

            }
        }
    }

    private func presentToHomeViewController(user: User) {
        let storyBoard = UIStoryboard(name: "Main", bundle: nil) // name: "Home" のところはエラーがでたので name: "Main" に変えた
        let homeViewController = storyBoard.instantiateViewController(identifier: "HomeViewController") as! HomeViewController
        homeViewController.user = user
        homeViewController.modalPresentationStyle = .fullScreen
        self.present(homeViewController, animated: true, completion: nil)

    }



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        registerButton.isEnabled = false
        registerButton.layer.cornerRadius = 10
        registerButton.backgroundColor = UIColor.rgb(red: 255, green: 221, blue: 187)

        emailTextField.delegate = self
        passwordTextField.delegate = self
        usernameTextField.delegate = self

        NotificationCenter.default.addObserver(self, selector: #selector(showKeyboard), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(hideKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)

        }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.navigationBar.isHidden = true
    }



    @objc func showKeyboard(notification: Notification) {

        let keyboardFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue

        guard let keyboardMinY = keyboardFrame?.minY else { return }
        let registerButtonMaxY = registerButton.frame.maxY
        let distance = registerButtonMaxY - keyboardMinY + 20

        let transform = CGAffineTransform(translationX: 0, y: -distance)


        // キーボードで入力場所が隠れてしまわないように画面を上にずらす処理 登録ボタン下側とキーボード上側
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: {
                        self.view.transform = transform
        })


        print("keyboardMinY : ", keyboardMinY, "registerButtonMaxY: ", registerButtonMaxY) // 基準の位置がきちんと取得できているか
        print("keyboardFrame : ", keyboardFrame) // 値が取得できているか確認
        print("showKeyboard is showing.") // キーボードがきちんと見える動作をしているかの確認
    }


    @objc func hideKeyboard() {


        // キーボードを閉じた時に画面位置を元の高さに戻す。
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: {
            self.view.transform = .identity
        })


        print("hideKeyboard is hide")
    }


    // 画面内のキーボード以外のところを選択するとキーボードが消える
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

}

extension ViewController: UITextFieldDelegate {

    func textFieldDidChangeSelection(_ textField: UITextField) {
        print("textField.text: ", textField.text)

        // ?? true は emailTextField.text?.isEmpty が nil であった場合に強制的に true にさせる指定
        let emailIsEmpty = emailTextField.text?.isEmpty ?? true
        let passwordIsEmpty = passwordTextField.text?.isEmpty ?? true
        let usernameIsEmpty = usernameTextField.text?.isEmpty ?? true

        if emailIsEmpty || passwordIsEmpty || usernameIsEmpty {
            registerButton.isEnabled = false
            // UIColor.swift のファイルを作成し、その中で color の数値を定義する関数を記述
            registerButton.backgroundColor = UIColor.rgb(red: 255, green: 221, blue: 187)
        } else {
            registerButton.isEnabled = true
            registerButton.backgroundColor = UIColor.rgb(red: 255, green: 141, blue: 0)
        }
        print("textField.text: ", textField.text)
    }
}

LoginViewController.swift
import UIKit
import Firebase
import PKHUD

class LoginViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!
    @IBOutlet weak var dontHaveAccountButton: UIButton!

    @IBAction func tappedDontHaveAccountButton(_ sender: Any) {

        // 戻るボタンを押した時、前の画面に戻る
        navigationController?.popViewController(animated: true)

    }

    @IBAction func tappedLoginButton(_ sender: Any) {
        HUD.show(.progress, onView: self.view)
        print("tapped Login Button")

        guard let email = emailTextField.text  else { return }
        guard let password = passwordTextField.text  else { return }

        Auth.auth().signIn(withEmail: email, password: password) { (res,err) in
            if let err = err {
                print("ログイン情報の取得に失敗しました: ", err)
                return
            }

            print("ログインに成功しました。")


            guard let uid = Auth.auth().currentUser?.uid else {return}
            let userRef = Firestore.firestore().collection("users").document(uid)

            userRef.getDocument{ (snapshot, err) in // firebaseからデータを引っ張ってくる処理
                if let err = err {
                    print("ユーザー情報の取得に失敗しました。 \(err)")

                    HUD.hide{ (_) in
                        HUD.flash(.error, delay: 1)
                    }

                    return
                }

                guard let data = snapshot?.data() else { return }
                let user = User.init(dic: data)


                print("ユーザー情報の取得に成功しました。\(user.name)")

                HUD.hide{ (_) in
//                    HUD.flash(.success, delay: 1)
                    HUD.flash(.success, onView: self.view, delay: 1) { (_) in
                        self.presentToHomeViewController(user: user)
                    }
                }

// "present" の引数について
// 第一引数: 遷移先のUIViewController
// 第二引数: アニメーションの指定(true: アニメーション有 / false: アニメーション無)
//  第三引数: コールバック関数

            }
        }
    }

    private func presentToHomeViewController(user: User) {
        let storyBoard = UIStoryboard(name: "Home", bundle: nil) // name: "Home" のところはエラーがでたので name: "Main" に変えた
        let homeViewController = storyBoard.instantiateViewController(identifier: "HomeViewController") as! HomeViewController
        homeViewController.user = user
        homeViewController.modalPresentationStyle = .fullScreen
        self.present(homeViewController, animated: true, completion: nil)

    }


    override func viewDidLoad() {
        super.viewDidLoad()
        loginButton.layer.cornerRadius = 10
        loginButton.isEnabled = false
        loginButton.backgroundColor = UIColor.rgb(red: 255, green: 221, blue: 187)

        emailTextField.delegate = self
        passwordTextField.delegate = self


    }
}

// MARK: - UITextFieldDelegate
extension LoginViewController: UITextFieldDelegate{

    func textFieldDidChangeSelection(_ textField: UITextField) {
        print("textField.text: ", textField.text)

        // ?? true は emailTextField.text?.isEmpty が nil であった場合に強制的に true にさせる指定
        let emailIsEmpty = emailTextField.text?.isEmpty ?? true
        let passwordIsEmpty = passwordTextField.text?.isEmpty ?? true


        if emailIsEmpty || passwordIsEmpty {
            loginButton.isEnabled = false
            // UIColor.swift のファイルを作成し、その中で color の数値を定義する関数を記述
            loginButton.backgroundColor = UIColor.rgb(red: 255, green: 221, blue: 187)
        } else {
            loginButton.isEnabled = true
            loginButton.backgroundColor = UIColor.rgb(red: 255, green: 141, blue: 0)
        }
        print("textField.text: ", textField.text)
    }
}
HomeViewController.swift
import Foundation
import UIKit
import Firebase

class HomeViewController: UIViewController {

    var user: User? {
        didSet {
            print("user?.name: ",user?.name)
        }
    }
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var emailLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var logoutButtton: UIButton!


    @IBAction func tappedLogoutButton(_ sender: Any) {
        handleLogout()
    }

    private func handleLogout() {
        do {
            try Auth.auth().signOut()
            presentToMainViewController()
        }catch (let err){
            print("ログアウトに失敗しました: \(err)")
        }

    }


    override func viewDidLoad() {
        super.viewDidLoad()

        logoutButtton.layer.cornerRadius = 10



        if let user = user { // 条件分岐でnilチェックをする

        nameLabel.text = user.name + "さんようこそ"
//        nameLabel.text = user!.name + "さんようこそ"
        emailLabel.text = user.email
            let dateString = dateFormatterForCreatedAt(date: user.createdAt.dateValue())
//        dateLabel.text = "作成日: " + user.createdAt.description
            dateLabel.text = "作成日: " + dateString
        }
    }




    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        confirmLoggedInUser()
    }



    private func confirmLoggedInUser() {
        if Auth.auth().currentUser?.uid == nil || user == nil {

            presentToMainViewController()

        }
    }


    private func presentToMainViewController(){
        let storyBoard = UIStoryboard(name: "Main", bundle: nil) // name: "Home" のところはエラーがでたので name: "Main" に変えた
        let ViewController = storyBoard.instantiateViewController(identifier: "ViewController") as! ViewController
        let navController = UINavigationController(rootViewController: ViewController)
        navController.modalPresentationStyle = .fullScreen
        self.present(navController, animated: true, completion: nil)
    }

    // シュミレータで作成日が数億秒で表示されるので、見やすくフォーマットする。
    private func dateFormatterForCreatedAt(date: Date) -> String{
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        formatter.timeStyle = .none
//        formatter.timeStyle = .long // localeのja_JPとセットで日本時間が表示される。
        formatter.locale = Locale(identifier: "ja_JP")
        return formatter.string(from: date)
    }



}
0

No Answers yet.

Your answer might help someone💌