Androidはワンツーパンチ 三歩進んで二歩下がる

プログラミングやどうでもいい話

iOSでRealmのデータファイルの場所の見つけ方

初期データのあらかじめ入ったRealmのファイルを用意しておき、
アプリに組み込んで使いたいと思っています。
それにはデータが入ったDBのファイルが必要です。
Realmの保存場所を特定する方法をメモしておきます。

前提

環境はXcode9.2、Swift4.0を使用しています。
初期データ作成用のXcodeプロジェクトを作っておきます。
実機かシミュレーターにRunしておきます。

シミュレーターにインストールした場合の場所

    // DBのファイルの場所
    print(Realm.Configuration.defaultConfiguration.fileURL!)

このコードでファイルパスを表示してくれます。
f:id:sakura_bird1:20180124152523p:plain

これをコピーします。

finderを開いてCommandキー+Shiftキー+Gを押します。

先ほどのパスを貼り付けます。
f:id:sakura_bird1:20180124153944p:plain:w200

先頭の「file://」は削除して移動します。

実機にインストールした場合

Xcodeのメニューから Window > Devices and Simulators を選択します。

実機にインストールされているアプリが一覧で表示されます。

アプリを選択します。

左下の設定アイコンをクリック > “Download Container…“を選択します。
f:id:sakura_bird1:20180124153205p:plain:w300


保存ダイアログが開きます。プロジェクトルートがデフォルトの保存場所になっています。
◯◯.xcappdataという名前がセットされているのでそのまま保存します。

Finderで保存した場所を開きます。
◯◯.xcappdataを右クリックして「パッケージの内容を表示」(英語表示の場合「“Show Package Contents”」)をクリックします。
f:id:sakura_bird1:20180124153450p:plain:w300

ここにあります。
AppData / Documents / default.realm
f:id:sakura_bird1:20180124153600p:plain:w300

以上です。




iOSのNsPredicateを使ってスペース区切りの文字列の検索条件を指定する&RealmでDBから読み込むメモ

こんにちは。自分の勉強メモです。
間違っていたらお声がけ下さると嬉しいです(●´ω`●)

前提

環境はXcode9.2、Swift4.0を使用しています。
Realmを使ったDBの処理を書いている最中です。

やりたいこと

よくあるキーワード検索がやりたいです。
・スペース区切りの文字列を入力された時に、スペースで文字列を分割する。
・対象のフィールドに分割した文字列がそれぞれ含まれているものを抽出する。

このように検索条件を入力したとすると
f:id:sakura_bird1:20180123224904p:plain


SQL文は次のようになります。

SELECT  "foods".* FROM "foods" WHERE (("foods"."name" LIKE '%たま%' OR "foods"."search_word" LIKE '%たま%') AND ("foods"."name" LIKE '%豆%' OR "foods"."search_word" LIKE '%豆%'))

この例では"foods"というテーブルから"name"または"search_word"というフィールドに
入力した文字列があった時にデータが抽出されます。

検索条件を指定するには

NsPredicateクラスを使っての検索条件を指定するのが定石のようです。
RealmでもNsPredicateがサポートされておりNSPredicate Cheatsheetという資料が用意されています。
NSPredicate Cheatsheet

前処理

検索する文字列をスペースで分割して配列に入れておきます。
有効な文字列が入っている前提です。

    let words = " たま 豆"
    // 全角スペースを半角スペースに置き換え余計なスペースはトリムする
    let newWords = words.replacingOccurrences(of: " ", with: " ").trimmingCharacters(in: .whitespacesAndNewlines)
    // componentsメソッドで指定の区切り文字で配列に分割する
    let wordsArray = newWords.components(separatedBy: " ")
    print(wordsArray) // ["たま", "豆"]

↑2018/03/18追記 トリム以外にも大文字小文字の区別も無くしたいという要望が多いと思うので、lowercased()などの関数を利用してもいいですね。

NsPredicateに条件を指定する

Swiftでは「let predicate = NSPredicate(format: "search_word CONTAINS %@", "たま")」
のようにformatに条件文を入れていきます。
NSPredicate - Foundation | Apple Developer Documentation

私の例ですと、SQLのLIKE、つまり文字列の部分一致に対応するオペレーターは
「CONTAINS」を使います。

また、比較したい文字列が複数あるかもしれない前提なので
NSPredicateオブジェクトを配列に格納してから「NSCompoundPredicate」クラスを利用してそれぞれの条件を結合します。
AND条件なので「andPredicateWithSubpredicates」を指定します。
比較したい文字列が1つしかなくてもこのコードで問題ありません。

    var predicates: [NSPredicate] = []

    for word in wordsArray {
      predicates.append(NSPredicate(format: "search_word CONTAINS %@ OR name CONTAINS %@", word, word))
    }

    print(predicates)// [search_word CONTAINS "たま" OR name CONTAINS "たま", search_word CONTAINS "豆" OR name CONTAINS "豆"]

    let compoundedPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)

    print(compoundedPredicate)//(search_word CONTAINS "たま" OR name CONTAINS "たま") AND (search_word CONTAINS "豆" OR name CONTAINS "豆")

Realmで検索する

filterメソッドに先程のNSCompoundPredicateオブジェクトをセットすればOKです。
公式ドキュメントはこちらです。
https://realm.io/docs/swift/latest/#queries

let result = realm.objects(Foods.self).filter(compoundedPredicate)

以上です。

Swift4のCodableプロトコルをRealmのモデルクラスに適用してJsonをパースした後にDBに投入するサンプル

RealmのモデルクラスにSwift4のCodableプロトコルを実装したいと思いましたのでサンプルを作りました。
環境はXcode9.2、Swift4.0を使用しています。
作成にあたってこちらのスライドを参考にさせていただきました。
ありがとうございます。
speakerdeck.com

サンプルの仕様

ローカルの「Kinds.json」を読み込み、モデルのオブジェクトに変換し
DBに書き込む。

実行結果

このようにコンソールに表示されます。

f:id:sakura_bird1:20180123005648p:plain:w300
f:id:sakura_bird1:20180123010744p:plain:w300


何かおかしな部分がございましたらお声がけくださると大変ありがたいです。

関連記事
sakura-bird1.hatenablog.com