カテゴリー: iOS

Swift3でRealmを使ってみる

はじめに

こんちには、はじめです。

現在勉強としてToDoアプリを作っており、その中でRealmを使用しています。

なので今回は自己学習の復習としてRealmを使って簡単に登録や検索ができるものとして、

単語の登録、一覧表示、検索が行えるアプリを作ってみました。

 

前提条件

Swift: 3.1
Realm: 2.7.0
Carthage: 0.22.0

 

事前準備

・Carthageのインストール
・プロジェクトの作成(SingleViewApplication)

Realmのインストール・設定

Carthageファイルの生成

ターミナルにてプロジェクトは以下で以下を実行

touch Cartfile

CarhageにてRealmをインストール

Carthageファイルに以下を記述

github "realm/realm-cocoa"

Realmをインストール

以下を実行してプロジェクトフォルダ配下にCarthageフォルダができていれば成功です。

carthage update --platform iOS

プロジェクト内でRealmが使用できるように設定

・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"
    }
}

 

一覧表示画面、登録画面の作成

storyboard作成

・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
}

 

Top画面にSearchBarを追加

SerachBarの追加

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)
    }
}

 

hajimenagasawa

シェア
執筆者:
hajimenagasawa
タグ: Swift

最近の投稿

Goの抽象構文木でコードを解析する

はじめに Goでアプリケーショ…

17時間 前

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

4週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前