初めての投稿になります。
私、まだ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
###TableViewController: UITableViewController
・NavigationControllerをEditor → Embed In → NavigationController の手順で追加
・BarButtonItemを追加し、InputViewControllerにドラッグしsegueを作成(Show, segueのIdentifier → toInputVC)
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に追加
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を記述することも可能です。
import RealmSwift
class ToDo: Object {
dynamic var title = ""
}
ToDoのタイトルとなるString型の変数を宣言します。
※通常のSwiftの記述方法と似ていますが、変数の宣言時にdynamicをつけるのを忘れないように注意してください。
#データを保存
データを保存する処理を記述していきます。
import UIKit
//追加
import RealmSwift
class InputViewController: UIViewController {
@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を上記のように記述
#データの呼び出し
アプリを一度閉じた後でも、データが引き継がれるように保存することはできましたが、これではまだ不十分です。
保存されたデータを表示するためにデータの取り出しを行う必要があります。
import UIKit
// 追加
import RealmSwift
class TableViewController: UITableViewController {
こちらも同様に、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{
}
}
// 追加 画面が表示される際などにtableViewのデータを再読み込みする
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
上記が、保存されたデータを取り出す処理になります。
最後に取り出したデータをTableViewに表示するための処理を書き加えていきます。
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
}
これでデータの取り出しの処理も完了です。
しかし、せっかくここまできたら、データを削除する処理も追加したいですね!
ということで・・・。
// 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アプリらしくなったのではないでしょうか。
最後にソースコードを全て記載しておきます。
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()
}
}
}
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)
}
}
import RealmSwift
class ToDo: Object {
dynamic var title = ""
}
最後までご覧いただき、ありがとうございます。
初めての投稿だったので、至らない点やわかりにくい点が多かったかと思いますが、お付き合いいただき、誠にありがとうございました。
この投稿がどなたかのお役に立てれば、幸いです。
では、失礼いたします。