こんちには、はじめです。
現在勉強としてToDoアプリを作っており、その中でRealmを使用しています。
なので今回は自己学習の復習としてRealmを使って簡単に登録や検索ができるものとして、
単語の登録、一覧表示、検索が行えるアプリを作ってみました。
Swift: 3.1
Realm: 2.7.0
Carthage: 0.22.0
・Carthageのインストール
・プロジェクトの作成(SingleViewApplication)
ターミナルにてプロジェクトは以下で以下を実行
touch Cartfile
Carthageファイルに以下を記述
github "realm/realm-cocoa"
以下を実行してプロジェクトフォルダ配下にCarthageフォルダができていれば成功です。
carthage update --platform iOS
・Generl > Linked Frameworks and Libraries に以下の二つを指定
/プロジェクトフォルダ/Carthage/Build/iOS/Realm.framework /プロジェクトフォルダ/Carthage/Build/iOS/RealmSwift.framework
・Build > Phases で「+マーク」をおして「Run Script」を追加
・Build > Phases > Run Scriptに以下を追加
$(SRCROOT)/Carthage/Build/iOS/Realm.framework $(SRCROOT)/Carthage/Build/iOS/RealmSwift.framework
以上でひとまずRealmが使えるようになりました。
・プロジェクト配下にModelsフォルダを作成
・Modelsフォルダ内にMyItems.swiftを作成し以下を記述
import Foundation import RealmSwift class MyItemObject: Object { dynamic var id: Int = 1 dynamic var itemName: String = "" override static func primaryKey() -> String { return "id" } }
・TOP画面はNavigationContoroller + TableView
・TOP画面右上の「+ボタン」から登録画面へ遷移(モーダル)
・登録画面でTextFieldと登録ボタンを追加
登録した単語一覧を表示する画面を作成
import UIKit class TopViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var myTableView: UITableView! override func viewDidLoad() { super.viewDidLoad() myTableView.delegate = self myTableView.dataSource = self } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .default, reuseIdentifier: "cell") return cell } }
次に単語を登録する画面を作成
import UIKit class AddItemViewController: UIViewController,UITextFieldDelegate { @IBOutlet weak var myTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() myTextField.delegate = self } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func textFieldShouldReturn(_ textField: UITextField) -> Bool { view.endEditing(true) return false } @IBAction func tapView(_ sender: Any) { view.endEditing(true) } }
登録ボタン押下後のデータ登録処理を追加します。
@IBAction func buttonTapped(_ sender: Any) { // 登録時に使用するIDを取得 let realm = try! Realm() // MyItemObjectモデルのデータをIdの降順で取得 let lastItem = realm.objects(MyItemObject.self).sorted(byKeyPath: "id", ascending: false) var addId: Int = 1 if lastItem.count > 0 { addId = lastItem[0].id + 1 } // 登録時に使用するIDを取得 let addItemObj = MyItemObject() addItemObj.id = addId addItemObj.itemName = myTextField.text! // 登録処理 try! realm.write { realm.add(addItemObj, update: true) } // 前の画面に戻る処理を作成 dismiss(animated: true, completion: nil) }
データの登録後Top画面が表示される際[viewDidLoad]は通らないため
[viewWillAppear]内にデータの取得処理を記述します。
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 一覧取得 let realm = try! Realm() let myItemsObj = realm.objects(MyItemObject.self) myItems = [] myItemsObj.forEach { item in myItems.append(item) } // Top画面表示時にテーブル内容をリロード myTableView.reloadData() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // セル数を返却 return myItems.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .default, reuseIdentifier: "cell") // itemNameをセルに表示 cell.textLabel?.text = myItems[indexPath.row].itemName return cell }
UISearchResultsUpdatingを継承してTableViewに追加して,
入力されるごとにあいまい検索を行った結果のみを表示するようにします。
var searchController = UISearchController() override func viewDidLoad() { searchController = UISearchController(searchResultsController: nil) searchController.searchResultsUpdater = self searchController.searchBar.sizeToFit() searchController.dimsBackgroundDuringPresentation = false searchController.hidesNavigationBarDuringPresentation = false myTableView.tableHeaderView = searchController.searchBar } func updateSearchResults(for searchController: UISearchController) { let predicate = NSPredicate(format: "itemName CONTAINS %@", searchController.searchBar.text!) let realm = try! Realm() let myItemsObj = realm.objects(MyItemObject.self).filter(predicate) myItems = [] myItemsObj.forEach { item in myItems.append(item) } // TableViewを更新 myTableView.reloadData() }
Realmはいろいろなところで使うことになると思います。
今回はあいまい検索を使いましたが、前方一致や後方一致、完全一致等の検索も今後使用する
必要があると思いますので、今後使用する機会があれば載せていこうと思います。
今回作ったアプリの最終的なソースは以下のようになります。
import Foundation import RealmSwift class MyItemObject: Object { dynamic var id: Int = 0 dynamic var itemName: String = "" override static func primaryKey() -> String { return "id" } }
import UIKit import RealmSwift class TopViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating { @IBOutlet weak var myTableView: UITableView! var searchController = UISearchController() var myItems: [MyItemObject] = [] override func viewDidLoad() { super.viewDidLoad() myTableView.delegate = self myTableView.dataSource = self searchController = UISearchController(searchResultsController: nil) searchController.searchResultsUpdater = self searchController.searchBar.sizeToFit() searchController.dimsBackgroundDuringPresentation = false searchController.hidesNavigationBarDuringPresentation = false myTableView.tableHeaderView = searchController.searchBar } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let realm = try! Realm() let myItemsObj = realm.objects(MyItemObject.self) myItems = [] myItemsObj.forEach { item in myItems.append(item) } myTableView.reloadData() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return myItems.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .default, reuseIdentifier: "cell") cell.textLabel?.text = myItems[indexPath.row].itemName return cell } func updateSearchResults(for searchController: UISearchController) { let predicate = NSPredicate(format: "itemName CONTAINS %@", searchController.searchBar.text!) let realm = try! Realm() let myItemsObj = realm.objects(MyItemObject.self).filter(predicate) myItems = [] myItemsObj.forEach { item in myItems.append(item) } myTableView.reloadData() } }
import UIKit import RealmSwift class AddItemViewController: UIViewController,UITextFieldDelegate { @IBOutlet weak var myTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() myTextField.delegate = self } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func textFieldShouldReturn(_ textField: UITextField) -> Bool { view.endEditing(true) return false } @IBAction func tapView(_ sender: Any) { view.endEditing(true) } @IBAction func buttonTapped(_ sender: Any) { // 現在のMaxIDを取得し、新規登録用のIDを生成 let realm = try! Realm() let lastItem = realm.objects(MyItemObject.self).sorted(byKeyPath: "id", ascending: false) var addId: Int = 1 if lastItem.count > 0 { addId = lastItem[0].id + 1 } // 登録 let addItemObj = MyItemObject() addItemObj.id = addId addItemObj.itemName = myTextField.text! debugPrint(addItemObj) try! realm.write { realm.add(addItemObj, update: true) } // 前の画面に戻る dismiss(animated: true, completion: nil) } }