LoginSignup
2
7

More than 3 years have passed since last update.

Realmを利用したiOSアプリの実装(データの追加・編集・更新・削除)

Last updated at Posted at 2020-05-24

この記事の内容

モバイル向けデータベース管理システム Realm を利用した、iOSアプリの開発
スクリーンショット 2020-05-24 13.05.26.png

参考にした記事

Realmを使ってTODOアプリを作ってみよう!/ Swift(Realmの使い方、初級編)

開発したアプリ

前掲の記事を参考にして、ToDo を追加しテーブルビューで表示することに加えて下記機能を実装した。

Remove All ボタン をクリックすると、ToDo を全て削除
Simulator Screen Shot - iPhone SE (2nd generation) - 2020-05-24 at 12.47.27.pngSimulator Screen Shot - iPhone SE (2nd generation) - 2020-05-24 at 12.47.33.png

・ToDo を表示しているテーブルビューのセルを左にスライドすると、その ToDo のみを削除
Simulator Screen Shot - iPhone SE (2nd generation) - 2020-05-24 at 12.47.11.png

・ToDo を表示しているテーブルビューのセルをクリックすると、ToDo を編集するためのアラートコントローラを表示
Simulator Screen Shot - iPhone SE (2nd generation) - 2020-05-24 at 12.47.19.png

・アラートコントローラの OKボタン をクリックすると、ToDo を更新
Simulator Screen Shot - iPhone SE (2nd generation) - 2020-05-24 at 12.47.23.pngSimulator Screen Shot - iPhone SE (2nd generation) - 2020-05-24 at 12.47.27.png

前提条件

① 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" と設定

コード

ToDoModel.swift
import Foundation
import RealmSwift

class TodoModel: Object{
    @objc dynamic var todo: String? = nil
}
ViewCotroller.swift
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 を改善したい

2
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7