ラベル Realm の投稿を表示しています。 すべての投稿を表示
ラベル Realm の投稿を表示しています。 すべての投稿を表示

2021年8月11日水曜日

RealmSwift はモデルだけ定義してあとは必要な箇所で RealmSwift を import するのが良さそう

RealmSwift はモデルだけ定義してあとは必要な箇所で RealmSwift を import するのが良さそう

概要

RealmSwift を扱う場合にモデルと CRUD 操作をどこに書くのがいいかなと悩んでいます 個人的にはシンプルに使いたいところで使う方式が一番しっくり来たので備忘録として残しておきます

環境

  • macOS 11.5
  • Xcode 12.5.1

モデルだけ定義する

Realm の基本的な使い方としてモデルを定義すると思うのですがそのモデル内では余計なことはしないようにします

単純にモデルだけを定義します

import RealmSwift

class BoardConfig: Object {
    @objc dynamic var name: String = ""
    @objc dynamic var point: Int = 0
}

View 側でモデルを使う

データの保存が取得は基本的に UIViewController などで行います view 側にも import RealmSwift が必要でかつデータにアクセスするために Realm() オブジェクトを生成する必要がありますが余計なことを考えなくて済むのでこの方法がベストだと思います

class BoardConfigViewController: UIViewController {
    override func viewDidLoad() {
        // データの保存
        let config = BoardConfig()
        config.name = "board1"
        config.point = 20
        let realm = try! Realm()
        try! realm.write {
            realm.add(config)
        }
        // データの取得
        let configs = realm.objects(BoardConfig.self)
        for config in configs {
            print(config)
        }
    }
}

上記では viewDidLoad で行っていますが Realm へのアクセスが必要な箇所で上記を呼び出す感じになります

Realm のオブジェクトを毎回生成するとあれなので Realm のオブジェクトはメンバー変数として扱っても良いかなと思います

アンチパターンっぽい書き方は

過去にモデルのクラスにデータを保存するメソッドやデータを取得するメソッドを作成していたのですがそれだとモデルを view 側でも扱うしモデル側でも扱う必要がありコードが重複している感がありました

CRUD 処理をまとめるという意味では良かったかもしれないのですがデータの変換などを考えると結局コードがごちゃごちゃするので微妙かなと思った感じです

モデルはあくまでもモデルでそれを view 側で変換したりするほうが結果的にキレイにコードになる印象です

最後に

結局シンプルなのが一番です

2018年3月26日月曜日

RealmSwift でマイグレートする方法

概要

RealmSwift ですでに定義したクラスにフィールドを追加したい場合はあると思います
リリースしているアプリの場合、ただ単純にフィールドを追加しただけだとエラーになってしまいます
その場合には正しい手順でマイグレートをしなければいけません

環境

  • macOS 10.13.2
  • Xcode 9.2 (9C40b)
  • RealmSwift 3.1.1

マイグレートする方法

AppDelete.swift の didFinishLaunchingWithOptions に以下を追加します

let config = Realm.Configuration(
  schemaVersion: 1,
  migrationBlock: { migration, oldSchemaVersion in
    if (oldSchemaVersion < 1) {
      // auto migrate
    }
  })

Realm.Configuration.defaultConfiguration = config

let realm = try! Realm()

これだけです、簡単
ただ、新規で追加したフィールドを何かしらの値で初期化するのであれば if 文内にそれを実装しなければなりません
例えば sum というフィールドを追加した場合、初期値が 0 でいいのであれば特に何もする必要はありません
Realm のクラス側でフィールドを 0 で定義すれば OK です
(※ RealmSwift では各フィールドはこちらのルールで初期化されます)
そうではなく例えば score と oldScore フィールドの足した値を sum フィールドに設定して初期化したい場合はその足し算のロジックを実装する必要があります

試してはいないのですがおそらく以下のような感じでできるはずです

if (oldSchemaVersion < 1) {
  migration.enumerateObjects(ofType: UserData.className()) { oldObject, newObject in
    let score = oldObject!["score"] as! Int
    let oldScore = oldObject!["oldScore"] as! Int
    newObject!["sum"] = score + oldScore
  }
}

また schemaVersion を今回「1」にしましたが次もマイグレートする場合は必ずここのバージョンを 2 なり 1 以上の値にしてくださいそうしないとマイグレートが行われません

最後に

RealmSwift でマイグレート処理を試してみました
処理を 1 つ Delegate に追加するだけなので非常に簡単にできます
クラスのスキーマのバージョン管理だけしっかりやる必要があるので定数などにしてちゃんと数字を追えるようにしておくと良いと思います

参考サイト

2017年10月4日水曜日

MacOS 版の Realm Browser を試してみた

概要

シミュレータを使ってアプリの動作確認をしている場合に Realm の中身を見たくなると思います
そんなときは Realm Browser を使うと良いです

環境

  • macOS X 10.12.6
  • Realm Browser 2.1.12

インストール

App Store でダウンロードできます
realmbrowser1.png

オープンソースとして公開されているので自分でビルドしてインストールすることも可能です
インストールできたら開きましょう

.realm ファイルを開く

起動すると以下のような画面になると思います
realmbrowser2.png

今回はシミュレータが作成した .realm ファイルを直接指定して中を確認してみます
.realm ファイルはターミナルで find コマンドなどを使うと簡単に探すことができると思います

  • sudo find / -name "*.realm"
/Users/hawksnowlog/Library/Developer/CoreSimulator/Devices/0E143484-CE4B-4DB2-8199-1807D471FC96/data/Containers/Data/Application/3E51916E-8681-4CB6-94EF-9A026C0E6A9E/Documents/default.realm
/Users/hawksnowlog/Library/Developer/CoreSimulator/Devices/9D4DB814-B7B0-4109-B4B7-E6B5B518B9BA/data/Containers/Data/Application/CC9860EF-C33B-4B27-9FF4-78DC71ED1E61/Documents/default.realm
/Users/hawksnowlog/Library/Developer/CoreSimulator/Devices/D2AC5D62-554C-4E34-AB65-F065147D5B5C/data/Containers/Data/Application/0E7BB6D6-3EF2-459B-9C93-DB8D39E95D28/Documents/default.realm

大抵は /Users/username/Library/Developer/CoreSimulator/Devices がシミュレータごとにあってその配下に default.realm ファイルがあると思います
これを直接指定しましょう
realmbrowser3.png

もしアクセスが必要だとみたいなダイアログが出た場合は「Allow」を選択しましょう

動作確認

開けると以下のような画面になると思います
realmbrowser4.png

レコードを選択すると Delete と Copy を選択できるようです
また、カラムの値の部分を Enter で選択すると編集できます
流石に新たに Models を追加することはできないようです
またマイグレーションもできないようです

ロックする機能もあり間違って削除したり値を変更させないようにすることもできるようです

最後に

MacOS で Realm Browser を試してみました
実機上の .realm ファイルを確認する場合は xcode を使って実機データ (.xcappdata) をダウンロードしてそれを展開するとその中に default.realm ファイルがあるのでそれを Realm Browser で開けば OK です

2017年9月3日日曜日

SpriteKit で Realm を使ってみる

概要

前回 SpriteKit で UserDefaults の使い方を紹介しました
実は UserDefaults には罠があってアプリを更新するとデータが消えてしまいます
なので、アプリが更新した際にデータが来ててほしくないようなデータを UserDefaults で管理すると大変なことになります
ということで今回は SpriteKit で Realm を使ってみました

環境

  • macOS X 10.12.6
  • Xcode 8.3.3 (8E3004b)
  • RealmSwift 2.8.3

ライブラリインストール

  • vim Podfile
pod 'RealmSwift'
  • pod install

Score.swift を作成

データを管理するクラスを作成します

import RealmSwift

class Score: Object{
    dynamic var name: String? = nil
    dynamic var score = 0
    dynamic var created = Date()
}

データを保存する関数をシーンファイルに追記

データを保存する関数を追加します
シーンファイルで定義するのが良いと思います

func insert() {
    let score: Score = Score()
    score.name = "hoge"
    score.score = 100
    score.created = Date()
    let realm = try! Realm()
    try! realm.write {
        realm.add(score)
    }
}

データを取得する関数をシーンファイルに追加

今度は取得する関数を定義します

func select() {
    let realm = try! Realm()
    let scoreList = realm.objects(Score.self).filter("score > 0").sorted(byKeyPath: "score", ascending: false)
    print(scoreList)
}

取得する条件はスコアが 0 以上かつスコアの大きい順となります
scoreList[0] とすれば最高スコアを取得することができます

ちなみに RealmSwift ではメソッドチェーンにより複数カラムでのソートはサポートしておらず例えば .sorted(byKeyPath: "created", ascending: false) を追加して作成日時でもソートしたいと思ってもできません

どうやらその場合は SortDescriptor を使ってソートするようです

追加した関数をコールする

あとはシーンファイルの touchDown などでノードを判定してコールするだけです

func touchDown(atPoint pos : CGPoint) {
    if let node = atPoint(pos) as? SKSpriteNode {
        if(node == show){
            if let _ = self.view {
                select()
            }
        } else if(node == save){
            if let _ = self.view {
                insert()
            }
        }
    }
}

動作確認

ちゃんとデータが保存されていると取得した際にコンソールに以下のようなデータ表示されるはずです

Results<Score> (
    [0] Score {
        name = hoge;
        score = 100;
        created = 2017-09-02 06:04:07 +0000;
    },
    [1] Score {
        name = hoge;
        score = 100;
        created = 2017-09-02 06:04:06 +0000;
    },
    [2] Score {
        name = hoge;
        score = 100;
        created = 2017-09-02 06:03:55 +0000;
    },
    [3] Score {
        name = hoge;
        score = 100;
        created = 2017-09-02 06:03:54 +0000;
    },
    [4] Score {
        name = hoge;
        score = 100;
        created = 2017-09-02 06:03:53 +0000;
    }
)

最後に

SpriteKit で Realm を使ってみました
結構簡単に使える感じです
気になったのはライブラリ自体のサイズがかなり大きそうなのでこれを使うだけで ipa ファイルの容量が増えそうです

SpriteKit では CoreData がなかなか難しいのでそういった意味では代替として Realm を採用するのには良いと思います

参考サイト