【Swift】UserDefaultsでログイン機能 - 簡易版
難しい機能を使わず、UserDefaultsで簡単にログイン機能を実装します。
ソースコード
初回ログイン時
//StoryBoardに設置したUIButton @IBAction func login(_ sender: Any) { //もしtextFieldに文字が入力されてるなら if textField.text != "" { let ud = UserDefaults.standard //ユーザー名をUDに保存 ud.set(textField.text, forKey: "userName") //次の画面に遷移するなど performSegue(withIdentifier: "goTimeLine", sender: nil) //もしtextFieldに何も入力されてなければ } else { //アラート let alert = EMAlertController(title: "ユーザー名を入力してください", message: "") //アクション let action = EMAlertAction(title: "OK", style: .cancel) //アラートにアクションを追加する alert.addAction(action: action) //アラートを表示 present(alert, animated: true, completion: nil) } }
UIButtonを設置し、”userName”キーとして保存してます。
何も入力してない時のアラートをEMAlertControllerで実装しました。
UIAlertActionの方だと、アラートを生成するコードが長く、コードを短くしてシンプルにまとめたほうが見栄えが綺麗になるので、EMの方を採用しました。
EMControllerをimportして、たった4行で実装できるのはめっちゃ便利ですよね。
次回ログインを省略
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) //もしユーザー名が保存されてるなら if let _ = UserDefaults.standard.object(forKey: "userName") { performSegue(withIdentifier: "goTimeLine", sender: nil) } }
僕は最初、viewWillAppear()の中に書きましたが、ログイン画面を省略できませんでした。
teratailで質問すると、
「viewWillAppear()はviewが生成される直前に呼ばれるので、遷移する処理は実行されません。」
「viewDidAppear()で実装してください」
と言われ、viewDidAppear()に書いたら、うまく動作しました。
viewのライフサイクルを学ばないといけませんねぇ。
デメリット
上記のコードの場合、「1度ログインしたユーザーは無条件でログインできる」こと。
例えば、一般的なサイトの場合、
会員登録する
↓
次回ログイン時に、個人情報を入力
↓→合致しない場合、再ログインが要求される
保存した個人情報と合致すればログインされる
というプロセスになっています。
対して、今回の記事で紹介したUserDefaultsによるログイン機能1は、入力したユーザー名は保存されるけど、次回以降は入力したデバイスを使えば誰であろうと無条件でログインできてしまいます。
今回のコードは、タイムラインでコメントなどを表示するアプリで使用したコードです。
別の記事で、入力したユーザー名がUserDefaultsに合致するかを判断する機能をご紹介します。
まとめ
100万人ものユーザーが利用するサービスだと、FirebaseやAWSなどの大規模なデータベースにユーザーの個人情報を保存するのでしょうが、個人で作るようなアプリならFirebaseやUserDefalutsで十分です。
別にリリースするつもりがなければ、UserDefaultsで事足りるでしょう。
【Xcode】Firebase関連のコードを消すと、Thread1 signal SIGBRTが消えた
新しくツイッター風のアプリを作ってて、初期画面が動作するからシミュレータを起動したら、Appdelegateの行でおなじみの”Thread1 signal SIGBRT”エラーが出ました。
そこで僕が行ったのは、
- UI部品のキャッシュが残ってないか
- 初期画面で実行できない処理はないか
- ImageViewに画像が設定されてないのが問題か
などを確認したことです。
しかし、上記らの確認を経ても、エラーは解消されませんでした。
ですが、あることを思いつきました。
実はFirebaseを使うつもりだったので、AppDelegate.swiftの方に、
import Firebase
.
.
.
FirebaseApp.configure()
を書いていました。
なんですけど、まだFirebaseを利用するコードは書いてませんでした。
もしかして、”Firebaseを利用する準備をしたのにFIrebaseを使ってないのが問題じゃね?”と思い、Firebase関連のコードを全て消しました。
すると..エラーが解消されました。
余計なコードは書くべきだはないのかもしれません。
【Swift】udemyでFirebaseを習ったので復習
Swiftで重要なFirebaseをudemyで学んだので、備忘録として書き記す。
- Firebaseを使用する準備
- データベースからデータを取得する流れ
- データベースの参照URLを生成
- データを保存するのに必要な変数を別クラスで宣言
- データベースのpost階層下のデータを取得する
- 取得したデータをセルに表示させる
- ユーザー名とコメントをデータベースに保存する
- まとめ
Firebaseを使用する準備
AppDelegateにFirebaseのimport文と使用許可?のコードを書く。
↓
ターミナルでpod関連をインストール
ターミナルで、
pod init
を打ち、生成されたPodfileに
pod
と書き、ターミナルで
pod install
と打つ。
使いたいViewControlleで
import Firebase
する。
データベースからデータを取得する流れ
- 保存したいデータを作成
- 指定したデータベースの階層下に保存
- データベースのURLを参照してデータを取り出す
- 取り出したデータを別に作ったPostクラスの変数に入れる
- セルなどに表示する
- 2に戻る
データベースの参照URLを生成
let ref = Database.database().reference()
データを保存するのに必要な変数を別クラスで宣言
データベースのpost階層下のデータを取得する
//保存するデータをuserNameとcommentとする //保存したデータは各postDataに格納される //それらのPostクラスをpost_Arrayでまとめて管理する //Post - データ群を持つデータ - userName, comment var post_Array = [Post]() var postData = Post() //データを取得する ref.child(“post”).observeSingleEvent(of: .value) { (snap, error) in //snapにはキーで名付けられたデータが辞書型で渡される //例:[“userName” : “Mike”]など let snapData = snap.value as? [String: NSDictionary] //もしデータがなければ if snapData == nil { return } // for (_, post) in snapData! { if let userName = post[“userName”] as? String, let comment = post[“comment”] as? String { //Post.swiftの変数にデータを入れる self.postData.userName = userName self.postData.comment = comment } //データをまとめてpost_Arrayに入れる self.post_Array.append(self.postData) } }
取得したデータをセルに表示させる
func tableView(…, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //セルを生成 let cell = tableView.dequeueReusableCell(withIdentifier: “cell”, for: indexPath) //Tag:1のUILabelをOutlet紐付けなしで紐付け let userNameLabel = cell.viewWithTag(1) as! UILabel //indexPath.rowに該当するPost()クラスのuserNameを入れる userNameLabel.text = posts[indexPath.row].userName let commentLabel = cell.viewWithTag(2) as! UILabel //indexPath.rowに該当するPost()クラスのuserNameを入れる commentLabel.text = posts[indexPath.row].comment return cell }
ユーザー名とコメントをデータベースに保存する
//post階層下にデータ群をまとめる配列?データを生成 //childByAutoId:階層下のデータを扱う階層名を自動生成? let rootRef = Database.database().reference(fromURL: “Firebaseで作ったデータベースのURL”).child(“post”).childByAutoId() //保存したいデータの型を宣言 let feed = [“userName”:Label.text , “comment”:textField.text] as [String: Any] //指定した階層にデータを保存 rootRef.setValue(feed)
まとめ
Userdefaults以上のデータ連携を可能にするFirebaseは、開発に重要な技術でありながら、初心者にはめちゃむずい。
udemyで初めてFirebaseに触れた時は、なんのこっちゃだった。
自分で写形したり、ほかの講座でまた触れたりしていくと、何となく理解できるようになった。
やはり、その技術にどれだけ触れられるかで理解度が変わってくる。
【Xcode】XCTestについて
XCTest(テスト)は、ViewController.swiftなどに書かれている関数をテストできる手法。
例えば、シミュレータや実機でアプリを起動しても、メソッドや関数がきちんと動作してるかは不明。
しかし、アプリではなく、関数という細部のテストをXCTestは可能にしてくれる。
(シミュレータが自動で起動してしまうが。)
XCTestを使用する手順は以下。
↓
まとめ
XCTestを調べていて驚いたのが、日本語の記事があまりないことだ。
少なくとも、日本ではあまり浸透していないのだろう。
仮に2018年の記事があっても、4000文字規模の詳しい記事はそうそうない。
やはり、応用的な技術は英語でしか手に入らないらしい。
しかし、XCAssertNil():Nilかどうかを判定する、などのテスト用のメソッドが用意されており、現場での開発で使えれば、注目されそう。