[Realm][Swift] 新しいタイプの導入

Realm がダイレクトにサポートしていないタイプを使う方法を説明します。

Realm は、非常に便利ですが、タイプとしてサポートされていない情報を保持しようとすると少し面倒だったので、その方法を説明します。

追加したかったタイプ

家計簿アプリを作りたかったので、Realm が Decimal をサポートするのを待っています。
しばらくかかりそうなので、自分で Decimal 相当を組み込んでみることにしました。

Decimal

10の冪乗で処理されるため、10進数の計算で誤差が発生しないことが特徴です。ですので、金融関連のアプリケーションでは必須と言えるタイプになっています。

MEMO
Double 等は、2の冪乗で処理され、有効桁数も限られているため、どうしても誤差が発生してしまいます。

独自タイプの定義

自分で Realm 自体に手を入れることは、あまり意味がないので、Realm でサポートしているタイプを組み合わせて保存することにしました。

金額を記憶させるタイプなので、”Currency” としました。

設計メモ
ドルでも、$1.23 などと、小数点以下の数字が出てくることがあります。
Web で調べたところ、小数点以下の数字のベースを補助通貨というそうで、ドルでは、セントが該当します。
大抵は、補助通貨は、ベース通貨の 1/100 である国が多いのですが、いくつかの国は、1/1000 までありました。

日本は、数少ない 1/1000 の補助通貨を持つ国です。円に対して、厘が、1/1000 となっています。

ということで、数字を 1000 倍して、Int64 に保存するよう設計しました。

Int64 は、9223372036854775807 (≒ 9.2e18) まで保持できて、その 1/1000 としても1.8e15 まで保持できるので、十分と判断しました。

Currency タイプ

後から、必要に応じて、Decimal からの initializer や、Int64 からの initializer を追加します。

モデルに独自タイプを持たせる

以下では、Realm で定義していた 口座のモデル (Account)に、初期残高を持たせるようにしたものです。

Account Model in Realm with Currency

(1) に初期残高を追加しました。よく考えれば、独自のタイプは、Realm での新しいタイプの Object になるので、この場合であれば、to-one relationship になるものでした。

to-one relationship

to-one relationship を追加して気付いたのですが、Realm では、to-one relationship は、optional で定義しないといけないという制限がありました。

そこで、optional にして定義しました。

# ここから、思ったより手間であることがわかり始めます。

optional

Realm がサポートしているタイプであれば、to-one relationship は単にプロパティということになるので、optional であることは必要ありません。

サポートしていないタイプを、プロパティのように持たせるために、to-one relationship という形で持たなければいけなくなりました。

アプリ設計者視点としては、そのプロパティを持つ Object (ここでは、Account) が初期化されたときに、Currency も初期化してくれて良いのです。

ですが、Realm 的な DB の観点からすると Object 間の関係を持っている要素を初期化等するときに、相手先の Object がすでに存在するかはわからないので、
optional にしてくれないと困る というのもよくわかります。

わかるのですが、optional としてしまうと、Account から Currency へのアクセスが常に optional かどうかのチェックが必要となり面倒です。

自分の場合は、すでにある程度コードを書いていたので、このような基本的なアクセスに変更が入るのは避けたいです。

wrapper

ということで、以下のような Wrapper を作って、できるだけアクセスAPIの変更がないようにしました。

example code

まとめ:独自タイプを Realm で定義したモデルに追加する

以下の手順で追加できます。

独自タイプを追加する
  • (必須)欲しいタイプを Object を継承して定義する
  • (必須)モデル要素からの to-one relationship としてモデルに追加する
  • (任意)wrapper accessor を定義すると便利

説明は以上です。
不明な点やおかしな点ありましたら、ご連絡いただけるとありがたいです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です