Firebase(「Google丸投げ」でiOSアプリ開発が恐ろしくラクになる!Firebaseの使い方)チュートリアルで詰まったところのメモ
はじめに
「Google丸投げ」でiOSアプリ開発が恐ろしくラクになる!Firebaseの使い方
こちらを試していた時に、そのままコピペだと動かないので下記の環境に対応するように書き直しました クラス名が異なるものもありました。
環境
Xcode9.2 Swift4.0.3 Firebase 4.13.0
このチュートリアル出来ること
Firebaseを使ってログイン・ログアウト機能を作ることが出来る データベースを使って追加と削除が出来る
チュートリアルどおりだと動かず詰まった箇所
こちらチュートリアル
switch errCode { case .errorCodeUserNotFound: self.showAlert("User account not found. Try registering") case .errorCodeWrongPassword: self.showAlert("Incorrect username/password combination") default: self.showAlert("Error: \(error.localizedDescription)") }
こちらが修正後
if let error = error { if let errCode = AuthErrorCode(rawValue: error._code) { //ここ異なる 参考(https://code.i-harness.com/ja/q/23b70bf) switch errCode { case .invalidEmail: self.showAlert("User account not found. Try registering") case .wrongPassword: self.showAlert("Incorrect username/password combination") default: self.showAlert("Error:\(error.localizedDescription)") } } return }
コード全部
LoginViewController.swift
import UIKit import FirebaseAuth class LoginViewController: UIViewController { @IBOutlet weak var emailField: UITextField! @IBOutlet weak var passwordField: UITextField! override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) //FIRAuthは→Authにする if let _ = Auth.auth().currentUser { self.signIn() } } override func viewDidLoad() { super.viewDidLoad() } @IBAction func didTapSignIn(_ sender: UIButton) { let email = emailField.text let password = passwordField.text Auth.auth().signIn(withEmail: email!, password: password!, completion: { (user, error) in guard let _ = user else { if let error = error { if let errCode = AuthErrorCode(rawValue: error._code) { //ここ異なる 参考(https://code.i-harness.com/ja/q/23b70bf) switch errCode { case .invalidEmail: self.showAlert("User account not found. Try registering") case .wrongPassword: self.showAlert("Incorrect username/password combination") default: self.showAlert("Error:\(error.localizedDescription)") } } return } //このreturnがいる return assertionFailure("user and error are nil") } self.signIn() }) } @IBAction func didRequestPasswordReset(_ sender: UIButton) { let prompt = UIAlertController(title: "To Do App", message: "Email:", preferredStyle: .alert) let okAciont = UIAlertAction(title: "OK", style: .default) { _ in let userInput = prompt.textFields![0].text if (userInput!.isEmpty) { return } Auth.auth().sendPasswordReset(withEmail: userInput!, completion: { (error) in if let error = error { if let errCode = AuthErrorCode(rawValue: error._code) { switch errCode { case .userNotFound: DispatchQueue.main.async{ self.showAlert("User account not found. Try registering") } default: DispatchQueue.main.async { self.showAlert("Error: \(error.localizedDescription)") } } } return } else { DispatchQueue.main.async { self.showAlert("You'll receive an email shortly to reset your password.") } } }) } prompt.addTextField(configurationHandler: nil) prompt.addAction(okAciont) self.present(prompt, animated: true, completion: nil) } func showAlert(_ message: String) { let alertController = UIAlertController(title: "To Do App", message: message, preferredStyle: UIAlertControllerStyle.alert) alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil)) self.present(alertController, animated: true, completion: nil) } func signIn() { self.performSegue(withIdentifier: "SignInFromLogin", sender: nil) } }
Item.swift
import Foundation import FirebaseDatabase class Item { var ref: DatabaseReference? var title: String? init(snapshot: DataSnapshot) { ref = snapshot.ref let date = snapshot.value as! Dictionary<String, String> title = date["title"]! as String } }
SignUpViewController.swift
import UIKit import FirebaseAuth class SignUpViewController: UIViewController { @IBOutlet weak var emailField: UITextField! @IBOutlet weak var passwordField: UITextField! override func viewDidLoad() { super.viewDidLoad() } @IBAction func didTapSignUp(_ sender: UIButton) { let email = emailField.text let password = passwordField.text Auth.auth().createUser(withEmail: email!, password: password!, completion: {(user, error) in if let error = error { if let errCode = AuthErrorCode(rawValue: error._code) { switch errCode { case .invalidEmail: self.showAlert("Enter a valid email.") case .emailAlreadyInUse: self.showAlert("Email already in use.") default: self.showAlert("Error: \(error.localizedDescription)") } } return } self.signIn() }) } @IBAction func didTapBackToLogin(_ sender: UIButton) { self.dismiss(animated: true, completion: {}) } func showAlert(_ message: String) { let alertController = UIAlertController(title: "To Do App", message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil)) self.present(alertController, animated: true, completion: nil) } func signIn() { performSegue(withIdentifier: "SignInFromSignUp", sender: nil) } }
ItemsTableViewController.swift
import UIKit import Firebase class ItemsTableViewController: UITableViewController { var user: User! var items = [Item]() var ref: DatabaseReference! private var databaseHandle: DatabaseHandle! override func viewDidLoad() { super.viewDidLoad() //ユーザーのログイン時の情報をuserにセット self.user = Auth.auth().currentUser //Firebaseデータベースのルート ref = Database.database().reference() startObservingDatabase() } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return items.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) let item = items[indexPath.row] cell.textLabel?.text = item.title return cell } override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { let item = items[indexPath.row] item.ref?.removeValue() } } @IBAction func didTapSignOut(_ sender: UIBarButtonItem) { do { //FIRAuth→Auth try Auth.auth().signOut() performSegue(withIdentifier: "SignOut", sender: nil) } catch let error { assertionFailure("Error signing out: \(error)") } } @IBAction func didTapAddItem(_ sender: UIBarButtonItem) { let prompt = UIAlertController(title: "To Do App", message: "To Do Item", preferredStyle:.alert) let okAction = UIAlertAction(title: "OK", style: .default){ (action) in let userInput = prompt.textFields![0].text if (userInput!.isEmpty) { return } self.ref.child("users").child(self.user.uid).child("items").childByAutoId().child("title").setValue(userInput) } prompt.addTextField(configurationHandler: nil) prompt.addAction(okAction) present(prompt, animated: true, completion: nil) } //データベースに加えられた変更も検知するリスナーをセット //初期値取得のために一度呼び出されデータに変更がある度に呼ばれる func startObservingDatabase() { //.value //FIRDataEventTypeValue:そのパスにあるコンテンツ全体の変更の検知と読み取りをする //FIRDataEventTypeValueイベントは参照するデータベースのデータが変更されると、子要素の変更も含めて毎回実行される databaseHandle = ref.child("users/\(self.user.uid)/items").observe(.value, with: { (snapshot) in var newItems = [Item]() for ItemSnapShot in snapshot.children { let item = Item(snapshot: ItemSnapShot as! DataSnapshot) newItems.append(item) } self.items = newItems self.tableView.reloadData() }) } deinit { ref.child("users/\(self.user.uid)/items").removeObserver(withHandle: databaseHandle) } }
参考文献
「Google丸投げ」でiOSアプリ開発が恐ろしくラクになる!Firebaseの使い方 Firebase認証エラーの読み込み
最後に
なにか間違いなどありましたらご指摘お願いします