質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

535閲覧

swift4で処理を一回だけにしたい。

Kaguya_4869

総合スコア116

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

1クリップ

投稿2019/07/15 08:08

#質問したいこと
現在swift4で、オリジナルアプリを作っています。そこで、ユーザーのログインが必要です。ログイン(サインアップ)はできるようになりましたが、その画面を表示するのを1回だけにしたいです。
#コード

swift4

1import UIKit 2import Firebase 3import FirebaseAuth 4 5class AccountViewController: UIViewController { 6 var acount: FirebaseApp! 7 8 @IBOutlet private weak var nameTextField: UITextField! 9 @IBOutlet private weak var emailTextField: UITextField! 10 @IBOutlet private weak var passwordTextField: UITextField! 11 12 //didTapSignUpButtonの挙動を一回にしたい。 13 @IBAction private func didTapSignUpButton() { 14 let email = emailTextField.text ?? "" 15 let password = passwordTextField.text ?? "" 16 let name = nameTextField.text ?? "" 17 18 Auth.auth().createUser(withEmail: email, password: password) { [weak self] result, error in 19 guard let self = self else { return } 20 if let user = result?.user { 21 let req = user.createProfileChangeRequest() 22 req.displayName = name 23 req.commitChanges() { [weak self] error in 24 guard let self = self else { return } 25 if error == nil { 26 user.sendEmailVerification() { [weak self] error in 27 guard let self = self else { return } 28 if error == nil { 29 // 仮登録完了画面へ遷移する処理 30 } 31 self.showErrorIfNeeded(error) 32 } 33 } 34 self.showErrorIfNeeded(error) 35 } 36 } 37 self.showErrorIfNeeded(error) 38 } 39 if (email == "" || password == "" || name == "") { 40 let message = "全てのフォームに記入して下さい。" 41 let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) 42 alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 43 present(alert, animated: true, completion: nil) 44 } 45 } 46 47 private func showErrorIfNeeded(_ errorOrNil: Error?) { 48 // エラーがなければ何もしません 49 guard let error = errorOrNil else { return } 50 51 let message = "エラーが起きました" // ここは後述しますが、とりあえず固定文字列 52 let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) 53 alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 54 present(alert, animated: true, completion: nil) 55 } 56 57 override func viewDidLoad() { 58 super.viewDidLoad() 59 60 // Do any additional setup after loading the view. 61 } 62 63} 64

#やってみたこと
色々なホームページを見て、作ってみましたが、うまく動きませんでした。
特にこちら↓のページを参考にさせていただきました。
https://www.mani-labo.net/entry/swift-lazy-closure
こちらにあるコードをぜひ使いたいと思っているのですが、恥ずかしながら、どこに入れればいいのか分かりません。
他に何かいいサイトだったり、実際にコードを教えていただけるのであれば、教えて下さい。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayabusabusash

2019/07/16 02:28

FirebaseのAuthの処理完了後に別の画面へ遷移するようですが、 現状どのあたりに問題があるのでしょうか? ボタンを連続でタップされたても大丈夫なようにすれば良いのでしょうか? また、lazyはviewWillAppear()などの複数回実行されるようなライフサイクルのイベント上で一度だけ実行したい時に使った方がいいと思います。 ボタンの処理にlazyを入れてしまうと、Authの処理がエラーになった際に再度タップしても処理が走らなくなってしまう気がします。
Kaguya_4869

2019/07/16 02:50

次回アプリを開くときには、サインアップの画面を表示させないようにしたいです。 アプリを開くと毎回サインアップしなければならないのを避けたいです。
hayabusabusash

2019/07/16 02:57 編集

返信ありがとうございます! なるほど、それならユーザーがサインアップ済みなのかどうかをどこかで保持しておいて それを起動時に確認し、任意の画面に遷移させる方が適切だと思います。 Authの処理完了後に画面遷移をすると思いますが、 その際にUserDefaultsなどでサインアップ完了のフラグを保持しておいて、 AppDelegateでフラグを確認して、サインアップ後の画面を表示するようにするのが無難かなと思います。 この辺が参考になるかもしれません。 ( http://blog.penginmura.tech/entry/2018/01/14/195323 )
Kaguya_4869

2019/07/16 03:03

Auth.auth().signIn(withEmail: email, password: password) { (user, error) in // [START_EXCLUDE] self.hideSpinner { if let error = error { self.showMessagePrompt(error.localizedDescription) return } self.navigationController!.popViewController(animated: true) } // [END_EXCLUDE] } こういう感じのコードを書けば良いですか? 違ったり、改良すべき点があれば教えていただけると助かります。
hayabusabusash

2019/07/16 03:08

そうですね... できればどんな画面の構成なっているか教えていただけないでしょうか? 例えば サインアップ画面 -> 完了画面 -> ホーム みたいな感じで、 どのように画面が遷移していくのかが知りたいです!
Kaguya_4869

2019/07/16 09:11

サインアップ画面→ホームというように画面遷移しています。
hayabusabusash

2019/07/16 14:04

長くなりそうなので回答の方に書かせていただきます。
guest

回答1

0

ベストアンサー

次回アプリを開くときには、サインアップの画面を表示させないようにしたいです。

アプリを開くと毎回サインアップしなければならないのを避けたいです。

こちらに関して、
AppDelegateでサインアップ後かどうかの判断をして初回に表示する画面を変えるのはどうでしょうか?

まずAuthの処理内でサインアップが成功した場合にUseDefaultsでサインアップ済みのフラグを保持します。

Swift

1Auth.auth().createUser(withEmail: email, password: password) { [weak self] result, error in 2 guard let self = self else { return } 3 if let user = result?.user { 4 let req = user.createProfileChangeRequest() 5 req.displayName = name 6 req.commitChanges() { [weak self] error in 7 guard let self = self else { return } 8 if error == nil { 9 user.sendEmailVerification() { [weak self] error in 10 guard let self = self else { return } 11 if error == nil { 12 // 仮登録完了画面へ遷移する処理 13 // サインアップ完了のフラグを保持する 14 UserDefaults.standard.set(true, forKey: "appSignUpStatusKey") 15 UserDefaults.standard.synchronize() 16 } 17 self.showErrorIfNeeded(error) 18 } 19 } 20 self.showErrorIfNeeded(error) 21 } 22 } 23 self.showErrorIfNeeded(error) 24 }

保持したフラグをAppDelegate内で読み込み、
サインアップ済みかどうかでRootViewControllerを変更します。

以下ではRootViewControllerをサインアップのViewControllerにして、
サインアップ済みならホームのViewControllerUINavigationControllerを使って表示するようにしています。(ViewControllerの初期化の部分は省いています。)

Swift

1class AppDelegate: UIResponder, UIApplicationDelegate { 2 3 var window: UIWindow? 4 5 6 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 7 8 // MARK: RootViewController 9 10 window = UIWindow(frame: UIScreen.main.bounds) 11 12 // ルートはサインアップのViewController 13 let rootVC = UINavigationController(rootViewController: /*AccountViewController*/) 14 15 // サインアップ済みならホームのViewControllerを表示 16 if UserDefaults.standard.bool(forKey: "appSignUpStatusKey") { 17 rootVC.pushViewController(/*HomeViewController*/, animated: false) 18 } 19 20 window?.rootViewController = rootVC 21 window?.makeKeyAndVisible() 22 23 return true 24 } 25}

投稿2019/07/16 14:23

編集2019/07/16 15:29
hayabusabusash

総合スコア767

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kaguya_4869

2019/07/16 21:54

すごい丁寧に教えてくださり、ありがとうございます! その方法でやってみます! もしまた何かあったら、お聞きするかもしれませんが、その時はよろしくお願いします。 ほんとうにありがとうございます!
Kaguya_4869

2019/07/26 09:55

ベストアンサーにした後に聞くのは、申し訳ないですが、 AppDelegateの let rootVC = UINavigationController(rootViewController: /*AccountViewController*/) で、 Use of unresolved identifier'UINavigationController(rootViewController:)' というエラーが出てきました。 どうすれば良いでしょうか?
hayabusabusash

2019/07/26 10:47

/*AccountViewController*/のところにAccountViewControllerを初期化するコードを入れてください。 もしAccountViewControllerをStoryboardで作っているなら、 UIStoryboard(name: "AccountViewController", bundle: nil).instantiateInitialViewController() ?? UIViewController() みたいな感じにすれば大丈夫だと思います。
Kaguya_4869

2019/07/29 10:42

実行すると、 Could not find a storyboard named 'AccountViewController' という理由で、落ちてしまいます。 名前はあっているのですが、どうしてか、分かりますか?
hayabusabusash

2019/07/30 00:05

AccountViewController.storyboardではなく他の名前のStoryboardでAccountViewControllerを作っていませんか? AccountViewControllerを作ったStoryboardの名前をnameに指定すればいいと思います。 AccountViewController.storyboardというファイルにAccountViewControllerだけを定義した前提でコードを書いてしまったのでわかりにくかったかもしれません。申し訳ありません。 もし複数のViewControllerを1つのStoryboardで作っているなら、 今回のように特定のViewControllerだけをStoryboardからインスタンス化したい場合 コードが冗長になりがちなので、一つのStoryboardに一つのViewControllerだけを定義することをお勧めします。 ( 参考 https://qiita.com/execjosh/items/72d68e6965a745693f05 )
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問