AWA with Realm (iOS)
AWA with Realm (iOS)
波戸 勇二[Yuji Hato]
INTRODUCTION自己紹介
System Engineer として SIer を経て、 2011 年サイバーエージェントに入社。複数の Ameba サービスにて、サーバサイド /Android/iOS を担当し、現在は AWA の iOSエンジニア。
Engineer
Twitter https://twitter.com/dekatotoro
GitHub https://github.com/dekatotoro
今日は
Realm に関しての使い方や Tips は様々な方が紹介しているので、 Realm を使ったアプリケーション全体の設計の紹介をします
Agenda
・ Realm を使う目的
・ Application Architecture
・なぜ Realm か
・ AWA とは
・ Coding Topics
・ Other Topics
洋楽・邦楽問わず、いつでもどこでも好きなだけ楽しむことができる月額定額制の音楽ストリーミングサービス
なぜ Realm か
なぜ Realmか
なぜ Realmか
・モデル / リレーションがクラス定義でらく
・パフォーマンスがよい
・クロスプラットフォームで Android 同じ設計ができる
・ Realm 使ってるとかっこよさそう
・ドキュメントの充実 & サポート
Realm を使う目的
Realmを使う目的
・ストレスフリーな UI/UX の実現
・通信量の削減
・表示速度 / パフォーマンスの向上
Application Architecture
サーバー
クライアント
クライアントとサーバのデータ同期
Application Architecture
サーバー
クライアント
Data の差分更新 /変更チェック
Application Architecture
差分のみ
サーバー
クライアント
オンデマンド保存
Application Architecture
必要になったら取得
Application Design
そのまえに…
AWA は Objective-C で実装しています
絶賛 Swift 書き換え中
※Bolts-iOS を使用しています
Application Design
API Server
RealmView ViewController Service
Models
Model の定義
Models
@interface EntityHoge : RLMObject
@property NSString *hogeId;@property NSString *name;@property NSInteger updatedAt;@property NSInteger storedAt;
// Finders+ (EntityHoge *) findById: (NSString *) hogeId;
@end
@implementation EntityHoge
+ (NSString *)primaryKey { return @"hogeId";}
+ (EntityHoge *) findById:(NSString *)hogeId { RLMRealm *realm = [RealmManager realm]; EntityHoge *hoge = [self objectInRealm:realm forPrimaryKey:hogeId]; return hoge;}@end
Model クラスに Finder なども定義しておくと便利。
Service
RealmObject を扱う Service を定義
Service
@implementation HogeService
- (EntityHoge *)read: (NSString *)hogeId{ [[RealmManager realm] refresh]; return [EntityHoge findById:hogeId];}
- (BFTask *)fetch:(NSString *)hogeId withModifiedSince:(NSInteger)modifiedSince{ return [[APIClient hogeData:hogeId modifiedSince:modifiedSince] continueWithExecutor:[RealmManager writeExecutor] withSuccessBlock:^id(BFTask *task) { // APIの戻りをチェックして差分を Realmに書き込み EntityHoge *hoge = [DataConverter toHoge:task.result]; [RealmManager commit:^(RLMRealm *realm) { [realm addOrUpdateObject:hoge]; }]; }];}@end
Service に read 、 fetch など決まった IF を用意することで扱いやすくなる。更新日時を渡すことで API からは変更 / 差分データのみを取得して Realm に保存。read はスレッドを跨ぐことを考慮して毎回 refresh を呼び出してから取得。
ViewController
ViewController からは Service を通してRealm を操作
ViewController
@property (nonatomic, strong) EntityHoge *hoge; - (void)loadFromRealm { self.hoge = [[HogeService shared] read:self.hogeId]; if (!self.hoge) { // no cache return; }
// Show cache}
- (void)loadFromAPI { NSInteger modifiedSince = (self.hoge) ? self.hoge.updatedAt : 0; [[[HogeService sharedService] fetch:self.hogeId withModifiedSince:modifiedSince] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) { // Realmから取得し直して Viewを更新 [self loadFromRealm];
return nil; }];}
Realm にデータがある場合は、 API に変更日を渡して変更 / 差分データのみ取得して更新があったデータのみ View を更新する。Bolts は非同期処理をメソッドチェーンで記述でき、 Thread も指定できるのでRealm を扱いやすい。 Notification は使ってない。
Other Topics
RLMRealm
Realmの path、初期化、 Realmインスタンスの取得、Migration、Write用スレッド queue取得などはwrapper classを作って纏めておくとよい
…+ (void)prepareRealms { static dispatch_once_t once; dispatch_once(&once, ^{
defaultDataPath = [RealmManager dataRealmPath:kRealmDataFileName]; defaultCachePath = [RealmManager cacheRealmPath:kRealmCacheFileName]; [RLMRealm setDefaultRealmPath:defaultCachePath]; [RLMRealm setDefaultRealmSchemaVersion:kCurrentSchemeVersion withMigrationBlock:^(RLMMigration *migration, uint64_t oldSchemaVersion) { }];
[RLMRealm defaultRealm]; });}
+ (RLMRealm *) realm { return [RLMRealm defaultRealm];}…
Notifications
Realm のデータ変更時に処理ができますがNotifications の詳細情報がないので、きめ細やかな UI 制御ができないため使っていない
@property(nonatomic, strong) RLMNotificationToken *token;…
self.token = [[LVPRealms realm] addNotificationBlock:^(NSString *note, RLMRealm * realm) { // updateUI}];
Migration
テーブル再構築処理かかないといけないので、モデルが大幅に変更になるような場合はつらい…
今のところ SchemaVersion 上げるだけで済んでいる
Compaction
メモリ系の Crash ログが増加してきたので中間テーブルの肥大化を懸念
1日以上経っていたら Compaction を実行している
まとめ
・複雑なデータを大量に扱うアプリでキャッ シュ用途として相性が良い
・ Realm と Bolts は意外に相性がよい
・クライアントにデータ保存する場合は サーバ含めたアプリケーション全体の 設計が大事
・ Realm チームのサポートが厚い
THANK YOU!