LoginSignup
48
45

More than 5 years have passed since last update.

RealmSwiftとUITableViewを使用してToDoアプリを作成

Last updated at Posted at 2016-08-01

初めての投稿になります。
私、まだSwiftを勉強し始めて1か月半程の新米であり、初めて投稿をさせていただきます。

現在、Realmを勉強しています。

勉強している際に、Objectにデータを追加する方法や、削除の方法はサンプルが沢山あり、勉強するのは容易だったのですが、
TableViewでのデータの扱いなど、具体的なサンプルがあまり見つからず、結構ハマってしまいました・・・。

自分で勉強したことの復習の意味も込めて、RealmSwift + UITableView でToDoアプリを制作してみました。

ソースコードはコチラから参照・ダウンロードしていただけます。

Realmの概要

Realmって何?
どうやってインストールするの?
といった疑問は、公式サイトがすごくわかりやすいので、参照してみてください。

※ちなみに今回は、cocoa podsを使ってプロジェクトにRealmSwiftを追加しました。

環境

OSX EI Capitan 10.11.6
Xcode 7.3.1
RealmSwift 1.0.2

まずは画面を作成

スクリーンショット 2016-08-01 21.16.27.png

TableViewController: UITableViewController

・NavigationControllerをEditor → Embed In → NavigationController の手順で追加

・BarButtonItemを追加し、InputViewControllerにドラッグしsegueを作成(Show, segueのIdentifier → toInputVC)

TableViewController.swift
import UIKit

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int {
        return 1
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexpath: NSIndexPath)->UITableViewCell {

        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

        return cell
    }
}

InputViewController: UIViewController

・UILabel
・UITextField → IBOutletをInputViewControllerに追加
・UIButton → IBActionをInputViewControllerに追加

InputViewController.swift
import UIKit

class InputViewController: UIViewController {

    @IBOutlet weak var titleTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        titleTextField.frame.size.height = 30
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    //Buttonが押された時の処理
    @IBAction func addButtonTapped(sender: AnyObject) {

    }
}

Realmを使用するためにクラス作成

Realmでデータを保存するためには、クラスが必要です。
今回は、Realmのクラスを記述するために、新たにファイルを追加しましたが、既存のファイルにclassを記述することも可能です。

ToDoRealmObject.swift
import RealmSwift

class ToDo: Object {
    dynamic var title = ""
}

ToDoのタイトルとなるString型の変数を宣言します。
※通常のSwiftの記述方法と似ていますが、変数の宣言時にdynamicをつけるのを忘れないように注意してください。

データを保存

データを保存する処理を記述していきます。

InputViewController.swift
import UIKit
//追加
import RealmSwift

class InputViewController: UIViewController {

InputViewController.swift
@IBAction func addButtonTapped(sender: AnyObject) {
        let newTodo = ToDo()

        // textFieldに入力したデータをnewTodoのtitleに代入
        newTodo.title = titleTextField.text!

        // 上記で代入したテキストデータを永続化するための処理
        do{
            let realm = try Realm()
            try realm.write({ () -> Void in
                realm.add(newTodo)
                print("ToDo Saved")
            })
        }catch{
            print("Save is Faild")
        }
 // 最後に、TableViewControllerに表示を切り替える       self.navigationController?.popToRootViewControllerAnimated(true)
    }

①import UIKitの下に、import RealmSwiftを追記
②InputViewController内の、addButtonTappedを上記のように記述

データの呼び出し

アプリを一度閉じた後でも、データが引き継がれるように保存することはできましたが、これではまだ不十分です。
保存されたデータを表示するためにデータの取り出しを行う必要があります。

TableViewController.swift
import UIKit

// 追加
import RealmSwift

class TableViewController: UITableViewController {

こちらも同様に、import RealmSwiftを追記します。

TableViewController.swift
class TableViewController: UITableViewController {

    // 追加
    var todoItem: Results<ToDo>!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 追加
        // 永続化されているデータを取りだす
        do{
            let realm = try Realm()
            todoItem = realm.objects(ToDo)
            tableView.reloadData()
        }catch{

        }

    }

    // 追加 画面が表示される際などにtableViewのデータを再読み込みする
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData()
    }

上記が、保存されたデータを取り出す処理になります。

最後に取り出したデータをTableViewに表示するための処理を書き加えていきます。

TableViewController.swift
 override func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int {

        // todoItemの数 = セルの数 
        return todoItem.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexpath: NSIndexPath)->UITableViewCell {
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

        // todoItemに代入されたデータをobject:NSArrayに代入
        let object = todoItem[indexpath.row]

        //cellのtextLabelのtextにobjectのtitleプロパティを代入 
        cell.textLabel?.text = object.title

        return cell
    }

これでデータの取り出しの処理も完了です。

しかし、せっかくここまできたら、データを削除する処理も追加したいですね!

ということで・・・。

TableViewController.swift
// TableViewのCellの削除を行った際に、Realmに保存したデータを削除する
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {


        if(editingStyle == UITableViewCellEditingStyle.Delete) {
            do{
                let realm = try Realm()
                try realm.write {
                    realm.delete(self.todoItem[indexPath.row])
                }
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            }catch{
            }
            tableView.reloadData()
        }
    }

TableViewのセルを左にスワイプし、Deleteボタンを押下すると、TableViewからセルが削除されることはもちろん、Realmに保存されていた該当データも削除されています。

より、ToDoアプリらしくなったのではないでしょうか。

最後にソースコードを全て記載しておきます。

TableViewController.swift
import UIKit
import RealmSwift

class TableViewController: UITableViewController {

    var todoItem: Results<ToDo>!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 永続化されているデータを取りだす
        do{
            let realm = try Realm()
            todoItem = realm.objects(ToDo)
            tableView.reloadData()
        }catch{

        }

    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int {
        return todoItem.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexpath: NSIndexPath)->UITableViewCell {
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

        let object = todoItem[indexpath.row]

        cell.textLabel?.text = object.title
        return cell
    }

    // TableViewのCellの削除を行った際に、Realmに保存したデータを削除する
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {


        if(editingStyle == UITableViewCellEditingStyle.Delete) {
            do{
                let realm = try Realm()
                try realm.write {
                    realm.delete(self.todoItem[indexPath.row])
                }
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            }catch{
            }
            tableView.reloadData()
        }
    }
}

InputViewController.swift
import UIKit
import RealmSwift

class InputViewController: UIViewController {
    @IBOutlet weak var titleTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        titleTextField.frame.size.height = 30
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func addButtonTapped(sender: AnyObject) {
        let newTodo = ToDo()

        // textFieldに入力したデータをnewTodoのtitleに代入
        newTodo.title = titleTextField.text!

        // 上記で代入したテキストデータを永続化
        do{
            let realm = try Realm()
            try realm.write({ () -> Void in
                realm.add(newTodo)
                print("ToDo Saved")
            })
        }catch{
            print("Save is Faild")
        }
        self.navigationController?.popToRootViewControllerAnimated(true)
    }
}

ToDoRealmObject.swift
import RealmSwift

class ToDo: Object {
    dynamic var title = ""
}

完成

スクリーンショット 2016-08-01 22.36.33.png

最後までご覧いただき、ありがとうございます。
初めての投稿だったので、至らない点やわかりにくい点が多かったかと思いますが、お付き合いいただき、誠にありがとうございました。

この投稿がどなたかのお役に立てれば、幸いです。

では、失礼いたします。

48
45
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
48
45