東急ハンズのiPad POSでRealmを使ってみた
この記事は、Realm Advent Calendar 2015の22日目の記事です。
ハンズラボの黒岩です。
エンジニアブログに書くのが初めてなので軽く自己紹介させてください。
iOSアプリ開発・MDMを使った運用を主に担当しており、現在は東急ハンズの内製でiPad POSレジを開発しています。
(まだ、数店舗での導入しておらず、東急ハンズ・ハンズビー・ピカロ全店のレジを順次iPadに置き換える予定)
東急ハンズのPOSでは、多くの場面でRealmを使っています。
どの場面で利用しているか
- 商品マスタ
- 金券マスタ
- 値引に関するマスタ
- 取引情報
- 支払情報
などの保存に利用。
Realm採用に至った理由
- パフォーマンスの良さ
- アップデートが頻繁に行われており、将来性がある
- 学習コストが少なく書き込み読み込みならすぐに理解が出来る
- 自動マイグレーションでとても楽
毎朝90万件のデータをアップデート
商品、金券など、毎朝最新マスタのダウンロードします。
商品マスタだけで90万件分のデータがあり、JSONデータをダウンロード・マッピングした後、Realmに書き込みます。
ダウンロード・マッピング・書き込み処理合わせても15分ほどで終わり、Realmの書き込み速度の速さが素晴らしい。(近い将来、全件更新ではなく、差分更新にする予定)
現状、Realmが起因でのクラッシュ等の問題も見られず、順調に運用出来ています。
マスタ取り込み・Realmへの書き込み
お金を扱う処理は、 NSDecimalNumber
で扱って計算を行いますが、
NSDecimalNumber
のままRealmに保存できないため、下記のように数値をStringに変換して保存します。
public class ItemRealm: Object {
/// 商品
public dynamic var name = ""
/// 商品コード
public dynamic var scanCode = ""
/// 売価
private dynamic var _sellingPrice = ""
....
public dynamic var sellingPrice: NSDecimalNumber {
get {
return NSDecimalNumber(string: _sellingPrice)
} set {
_sellingPrice = newValue.stringValue
}
}
....
1度に1万件ずつJSONデータを ObjectMapper
でObjectにマッピングを行い、RealmObject
に変換して書き込みます。
public func save<T: Master>(master: T, _ key: String) -> DefaultTask {
guard let items = Mapper<T>().mapArray(jsonData.arrayObject) as [T]? else {
return
}
....
do {
let realm = try Realm()
try realm.write { () -> Void in
items.forEach {
$0.save(realm)
}
}
}
}
....
関連・オプショナル
取引に支払、複数の取引明細をもつなど、関連で簡潔に定義できる。
必要な場合のみセットするものはオプショナルで持つなどして対応できる。
// 取引
public class TransactionRealm: Object {
/// 支払
public dynamic var payment: PaymentRealm?
/// 取引明細
public let details = List<TransactionDetailRealm>()
/// 収入印紙種別
public let revenueStampType = RealmOptional<Int>()
マイグレーションが楽
Realm最新バージョンでは、例えフィールドがいくつ増えようとも増えても自動でマイグレーションが行われるため、
schemaVersionをインクリメントするだけの修正で済みます。
let config = Realm.Configuration(schemaVersion: 2, migrationBlock: { migration, oldSchemaVersion in
})
Realm.Configuration.defaultConfiguration = config
マッピングが辛かった
ObjectMapperのマッピングの抜け漏れがあって、Realmに保存されないフィールドが多々あった。
やはり手メンテ・目視でもメンテは辛い。
public func mapping(map: Map) {
name <- map["name"]
scanCode <- map["scanCode"]
sellingPrice <- (map["sellingPrice"], DecimalNumberTransform())
....
おわりに
軽く上辺だけ話になり、Realmの概要みたいになりましたが、
使い勝手がよくパフォーマンスの良いのでぜひ使ってみてください。