環境
- OS:MacOS Catalina 10.15.1
- Swift 5.1
- Xcode 11.2.1
作成するアプリのイメージ
ユーザーを管理するアプリを作成します。
理由としては、以下の3点。
- 自分で定義した型を使う
- CRUDが全部できる
- かんたん
ユーザーである必要はないんだけど、型が考えやすいので。
Firebaseの環境設定
環境設定に関しては、下記の記事を参照してください。
iOSでFirebaseを使用して、データベースに対してCRUDを試してみる。 - Qiita
一覧画面を作成しよう
ユーザー型の定義
ユーザーは、以下の要素を持つことにします。
import UIKit
import Firebase
struct User {
var name: String = ""
var age: Int = 0
var favoriteFood: String = ""
}
StoryBoardを作成する
画像のように、NavigationControllerとTableView、TableCellを配置します。
TableCellにIDをつけておきましょう。(今回はUserTableCellにしました)
TableCellに3つラベルを配置します。後で使うのでTagもつけておきます。
ViewControllerを作成する
Firebaseからの応答は、直接構造体に格納できません。そこで、[String: Any]から自分に代入するメソッドを追加します。
import UIKit
import Firebase
struct User {
var name: String = ""
var age: Int = 0
var favoriteFood: String = ""
/// Dictionaryから、自分自身に代入します。
/// - Parameter dictionary: User型
mutating func setFromDictionary(_ dictionary: [String: Any]) {
name = dictionary["name"] as? String ?? ""
age = dictionary["age"] as? Int ?? 0
favoriteFood = dictionary["favoriteFood"] as? String ?? ""
}
}
TableViewに取得したユーザーを表示するプログラムを書きます。
import UIKit
import Firebase
class UsersListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var usersTableView: UITableView!
var users: [User]!
override func viewDidLoad() {
super.viewDidLoad()
usersTableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let ref = Database.database().reference()
ref.child("Users").observe(.value) { (snapshot) in
// 初期化
self.users = []
for data in snapshot.children {
let snapData = data as! DataSnapshot
let dictionarySnapData = snapData.value as! [String: Any]
var user = User()
// 取得した内容をユーザー型にセット
user.setFromDictionary(dictionarySnapData)
// ユーザーリストに追加
self.users.append(user)
}
// すべてユーザーリストに格納したら、TableViewを更新する。
self.usersTableView.reloadData()
}
}
// MARK: - TableViewMethod
// セルの個数
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let _users = users else { return 0 }
return _users.count
}
// セルに値をセット
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = usersTableView.dequeueReusableCell(withIdentifier: "UserTableCell", for: indexPath)
let user = users[indexPath.row]
let nameLabel = cell.viewWithTag(1) as! UILabel
nameLabel.text = user.name
let ageLabel = cell.viewWithTag(2) as! UILabel
ageLabel.text = String(user.age)
let favoriteLabel = cell.viewWithTag(3) as! UILabel
favoriteLabel.text = user.favoriteFood
return cell
}
// セルタップ時
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
}
編集画面を作成しよう
StoryBoardを作成する
新しいViewControllerを配置して、TextField3つとButtonを1つ追加します。
あと一覧画面に遷移用のボタンを追加しておきます。
ViewControllerを作成する
Dictionaryでやり取りするので、Userに以下のメソッドを追加します。
/// Dictionaryに変換します。
var toDictionary: [String: Any] {
return [
"name": name,
"age": age,
"favoriteFood": favoriteFood
]
}
追加用の処理を書きます。
import UIKit
import Firebase
class UsersEditViewController: UIViewController {
@IBOutlet weak var nameText: UITextField!
@IBOutlet weak var ageText: UITextField!
@IBOutlet weak var favoriteFoodText: UITextField!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@IBAction func submitButtonTapped(_ sender: UIButton) {
let ref = Database.database().reference()
// 入力内容をUserインスタンスに入れる
var newUser = User()
newUser.name = nameText.text!
newUser.age = Int(ageText.text!) ?? 0
newUser.favoriteFood = favoriteFood.text!
// データを登録
ref.child("Users").childByAutoId().setValue(newUser.toDictionary)
// 登録後 前画面に戻る
self.navigationController?.popViewController(animated: true)
}
}
実行結果
更新モードを作成しよう
前画面からキーを受け取れるようにし、
キーを指定して、データに値をセットします。
(下記以外にも色々追加していますが、詳細については最後に貼ります。)
import UIKit
import Firebase
class UsersEditViewController: UIViewController {
@IBOutlet weak var nameText: UITextField!
@IBOutlet weak var ageText: UITextField!
@IBOutlet weak var favoriteFoodText: UITextField!
@IBOutlet weak var submitButton: UIButton!
var user: User!
// 前画面からキーを受け取る
var key: String!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 前画面から受け取った値をセットする
// (ホントはキーのみ受け取って再検索するほうが良さそう)
nameText.text = user.name
ageText.text = String(user.age)
favoriteFoodText.text = user.favoriteFood
}
// MARK: - EventFunctions
@IBAction func submitButtonTapped(_ sender: UIButton) {
let ref = Database.database().reference()
// 入力内容をUserインスタンスに入れる
var newUser = User()
newUser.name = nameText.text!
newUser.age = Int(ageText.text!) ?? 0
newUser.favoriteFood = favoriteFoodText.text!
// データを更新
ref.child("Users").child(key).setValue(newUser.toDictionary)
// 処理終了後 前画面に戻る
self.navigationController?.popViewController(animated: true)
}
削除機能を作成しよう
スワイプ時のTableViewMethodを追加します。
// セルスワイプ時(削除)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) ->
UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "削除") { (action, sourceView, completionHandler) in
completionHandler(true)
let ref = Database.database().reference()
ref.child("Users").child(self.keys[indexPath.row]).removeValue()
}
let swipeAction = UISwipeActionsConfiguration(actions: [delete])
swipeAction.performsFirstActionWithFullSwipe = true
return swipeAction
}
ソースコード
ソースコードはGitHubに置いてますので、欲しい人はどうぞ。
SampleFirebase
まとめ
とりあえず基本のCRUDをアプリっぽく再現できたぞ!
今回はRealTimeDatabaseを使用しましたが、CloudFireStoreのほうが今はおすすめらしいので、そっちも時間があればやってみます。