31
AWA with Realm (iOS)

AWA with Realm

Embed Size (px)

Citation preview

Page 1: AWA with Realm

AWA with Realm (iOS)

Page 2: AWA with Realm

波戸 勇二[Yuji Hato]

INTRODUCTION自己紹介

System Engineer として SIer を経て、 2011 年サイバーエージェントに入社。複数の Ameba サービスにて、サーバサイド /Android/iOS を担当し、現在は AWA の iOSエンジニア。

Engineer

Twitter https://twitter.com/dekatotoro

GitHub https://github.com/dekatotoro

Page 3: AWA with Realm

今日は

Realm に関しての使い方や Tips は様々な方が紹介しているので、 Realm を使ったアプリケーション全体の設計の紹介をします

Page 4: AWA with Realm

Agenda

・ Realm を使う目的

・ Application Architecture

・なぜ Realm か

・ AWA とは

・ Coding Topics

・ Other Topics

Page 5: AWA with Realm
Page 6: AWA with Realm

洋楽・邦楽問わず、いつでもどこでも好きなだけ楽しむことができる月額定額制の音楽ストリーミングサービス

Page 7: AWA with Realm

なぜ Realm か

Page 8: AWA with Realm

なぜ Realmか

Page 9: AWA with Realm

なぜ Realmか

・モデル / リレーションがクラス定義でらく

・パフォーマンスがよい

・クロスプラットフォームで Android 同じ設計ができる

・ Realm 使ってるとかっこよさそう

・ドキュメントの充実 & サポート

Page 10: AWA with Realm

Realm を使う目的

Page 11: AWA with Realm

Realmを使う目的

・ストレスフリーな UI/UX の実現

・通信量の削減

・表示速度 / パフォーマンスの向上

Page 12: AWA with Realm

Application Architecture

Page 13: AWA with Realm

サーバー

クライアント

クライアントとサーバのデータ同期

Application Architecture

Page 14: AWA with Realm

サーバー

クライアント

Data の差分更新 /変更チェック

Application Architecture

差分のみ

Page 15: AWA with Realm

サーバー

クライアント

オンデマンド保存

Application Architecture

必要になったら取得

Page 16: AWA with Realm

Application Design

Page 17: AWA with Realm

そのまえに…

AWA は Objective-C で実装しています

絶賛 Swift 書き換え中

※Bolts-iOS を使用しています

Page 18: AWA with Realm

Application Design

API Server

RealmView ViewController Service

Page 19: AWA with Realm

Models

Model の定義

Page 20: AWA with Realm

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 なども定義しておくと便利。

Page 21: AWA with Realm

Service

RealmObject を扱う Service を定義

Page 22: AWA with Realm

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 を呼び出してから取得。

Page 23: AWA with Realm

ViewController

ViewController からは Service を通してRealm を操作

Page 24: AWA with 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 は使ってない。

Page 25: AWA with Realm

Other Topics

Page 26: AWA with Realm

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];}…

Page 27: AWA with Realm

Notifications

Realm のデータ変更時に処理ができますがNotifications の詳細情報がないので、きめ細やかな UI 制御ができないため使っていない

@property(nonatomic, strong) RLMNotificationToken *token;…

self.token = [[LVPRealms realm] addNotificationBlock:^(NSString *note, RLMRealm * realm) { // updateUI}];

Page 28: AWA with Realm

Migration

テーブル再構築処理かかないといけないので、モデルが大幅に変更になるような場合はつらい…

今のところ SchemaVersion 上げるだけで済んでいる

Page 29: AWA with Realm

Compaction

メモリ系の Crash ログが増加してきたので中間テーブルの肥大化を懸念

1日以上経っていたら Compaction を実行している

Page 30: AWA with Realm

まとめ

・複雑なデータを大量に扱うアプリでキャッ シュ用途として相性が良い

・ Realm と Bolts は意外に相性がよい

・クライアントにデータ保存する場合は サーバ含めたアプリケーション全体の 設計が大事

・ Realm チームのサポートが厚い

Page 31: AWA with Realm

THANK YOU!