はじめに
「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認証エラーの読み込み
最後に
なにか間違いなどありましたらご指摘お願いします