この記事の内容
モバイル向けデータベース管理システム Realm を利用した、iOSアプリの開発
参考にした記事
Realmを使ってTODOアプリを作ってみよう!/ Swift(Realmの使い方、初級編)
開発したアプリ
前掲の記事を参考にして、ToDo を追加しテーブルビューで表示することに加えて下記機能を実装した。
・Remove All ボタン をクリックすると、ToDo を全て削除
・ToDo を表示しているテーブルビューのセルを左にスライドすると、その ToDo のみを削除
・ToDo を表示しているテーブルビューのセルをクリックすると、ToDo を編集するためのアラートコントローラを表示
・アラートコントローラの OKボタン をクリックすると、ToDo を更新
前提条件
① CocoaPods Realm の導入、テキストボックスに入力した文字を保存する処理を実装する方法は前掲の記事を参照してください。
② 今回のアプリは、Realm の利用方法を確認するために開発しました。その為、 Apple が策定した Human Interface Guidelines は考慮していません。
開発環境
項目 | |
---|---|
PC | MacBook Air 2017 |
IDE | Xcode Ver. 11.4.1 |
言語 | Swift 5.2.2 |
データベース | Realm |
コード管理 | GitHub |
Realm とは
モバイル向けデータベース管理システム
Main.storyboard
項目 | 属性 | 備考 |
---|---|---|
ViewCotroller | UIViewController | ViewCotroller.swift と紐付け |
Navigation Bar | UINavigationBar | Title を "TestApp" と設定 |
ToDoTextField | UITextField | このテキストフィールドに入力した文字を ToDo として保存 |
Add Button | UIButton | ボタンの色:青 角は丸く |
Remove All Button | UIButton | ボタンの色:赤 角は丸く |
ToDoTableView | UITableView | 保存されている ToDo を表示 |
testCell | UITableViewCell | Identifier を "testCell" と設定 |
コード
import Foundation
import RealmSwift
class TodoModel: Object{
@objc dynamic var todo: String? = nil
}
import UIKit
import RealmSwift
class ViewController: UIViewController,UITextFieldDelegate,UITableViewDelegate {
@IBOutlet weak var todoTextFiled: UITextField!
@IBOutlet weak var todoTableView: UITableView!
@IBOutlet weak var addButton: UIButton!
@IBOutlet weak var removeAllButton: UIButton!
var itemList: Results<TodoModel>!
// Add ボタンをクリックした際に実行する処理
@IBAction func tapAddButton(_ sender: Any) {
let instancedTodoModel:TodoModel = TodoModel()
instancedTodoModel.todo = self.todoTextFiled.text
let realmInstance = try! Realm()
try! realmInstance.write{
realmInstance.add(instancedTodoModel)
}
self.todoTableView.reloadData()
}
// Remove All ボタンをクリックした際に実行する処理
@IBAction func tapRemoveAllButton(_ sender: Any) {
let realmInstance = try! Realm()
try! realmInstance.write{
realmInstance.deleteAll()
}
self.todoTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// UITableViewDataSource を self に設定
self.todoTableView.dataSource = self
// UITableViewDelegate を self に設定
self.todoTableView.delegate = self
// ボタンの角を丸くする設定
addButton.layer.cornerRadius = 5
removeAllButton.layer.cornerRadius = 5
let realmInstance = try! Realm()
self.itemList = realmInstance.objects(TodoModel.self)
self.todoTableView.reloadData()
}
}
extension ViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.itemList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let testCell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "testCell")!
let item: TodoModel = self.itemList[(indexPath as NSIndexPath).row]
testCell.textLabel?.text = item.todo
return testCell
}
// テーブルビューの編集を許可
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// テーブルビューのセルとデータを削除
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
// データを削除
let realmInstance = try! Realm()
try! realmInstance.write {
realmInstance.delete(itemList[indexPath.row])
}
// セルを削除
tableView.deleteRows(at: [indexPath as IndexPath], with: UITableView.RowAnimation.automatic)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("セル\(indexPath)が選択されました")
showAlertController(indexPath)
}
// テーブルビューのセルをクリックしたら、アラートコントローラを表示する処理
func showAlertController(_ indexPath: IndexPath){
let alertController: UIAlertController = UIAlertController(title: "\(String(indexPath.row))番目の ToDo を編集", message: itemList[indexPath.row].todo, preferredStyle: .alert)
// アラートコントローラにテキストフィールドを表示 テキストフィールドには入力された情報を表示させておく処理
alertController.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = self.itemList[indexPath.row].todo})
// アラートコントローラに"OK"ボタンを表示 "OK"ボタンをクリックした際に、テキストフィールドに入力した文字で更新する処理を実装
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {
(action) -> Void in self.updateAlertControllerText(alertController,indexPath)
}))
// アラートコントローラに"Cancel"ボタンを表示
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
// "OK"ボタンをクリックした際に、テキストフィールドに入力した文字で更新
func updateAlertControllerText(_ alertcontroller:UIAlertController, _ indexPath: IndexPath) {
// guard を利用して、nil チェック
guard let textFields = alertcontroller.textFields else {return}
guard let text = textFields[0].text else {return}
// UIAlertController に入力された文字をコンソールに出力
print(text)
// Realm に保存したデータを UIAlertController に入力されたデータで更新
let realmInstance = try! Realm()
try! realmInstance.write{
itemList[indexPath.row].todo = text
}
self.todoTableView.reloadData()
}
}
実装のポイント
・テーブルビューのセルを削除するだけでは、それに紐づく Realm に保存したデータは削除されない。そのため、セルとデータをそれぞれ削除する処理を実装する必要がある。
感想
・CocoaPods Realm の導入に少しつまづいた
・アラートコントロールを利用した編集・更新処理のコードが煩雑になったので、リファクタリングしたい
・データベースと連携した iOS アプリを開発できるようになり、開発の幅が広まったと思う
・Human Interface Guidelines に沿うように UI を改善したい