LoginSignup
2
2

More than 5 years have passed since last update.

Realm+JSONが使い勝手悪いので、リレーションはるために考えてみた。

Last updated at Posted at 2016-03-15

まず

ツッコミ大歓迎!!

未熟な部分が多いと思うので、ぜひご教授願います。


Realm+JSONは素晴らしいと思います。
以前からMANTLEを利用していたので、同じノリで使えるのかと思っていましたがリレーション周りがあまりよくありませんでした。

こんなケース

公式によく乗っている例だと、以下のようなjsonで使っています。 ( そもそも、こういうケースしか想定していないのだと思いますが... )

{
  "article" : {
    "id"          : 1,
    "title"       : "title",
    "comments" : [
      {"id" : 1, "text" : "text"},
      {"id" : 2, "text" : "text"},
      {"id" : 3, "text" : "text"}
    ]
  }
}

こういうのは公式を参考にしてください。

今回、書くのは以下のような形式です。

{
  "article" : {
    "id"          : 1,
    "title"       : "title",
    "comment_ids" : [
      1,
      2,
      3
    ] 
  }
}

上記の場合は、どうすればいいでしょうか? ( ネットの記事を見てもあまり書かれておらず、自分も迷っていました。 )

自分なりの回答

Realm+JSON + NSValueTransformer

Realm+JSONは割愛します。 ( Githubをご参考ください。 )

NSValueTransformer

NSValueTransformerは、クラスの必要なメソッドを用意してインスタンスに対して - transformedValue: を呼べば値の変換を行ってくれます。

NumberTransformer *t = [[NumberTransformer alloc] init];
[t transformedValue:@"1"];  // => @(1)

これをモデルに対して行ってしまおうということです。

NSValueTransformerの実装

必要なメソッドを用意します。

  • + (Class)transformedValueClass
  • - (id)transformedValue:(id)value

普通のNSValueTransformerのsubclassだと上記2つのメソッドが必要なのですが、Web APIだとjson形式のものが多いと思うので独自にメソッドを定義してみます。

  • - (id)transformWithDictionary:(NSDictionary *)dic

  • + (Class)transformedValueClass

変換後のクラスを返します。
NSNumberだったら[NSNumber class]

  • - (id)transformedValue:(id)value

コメントアウト、または削除しても構いません。

  • - (id)transformWithDictionary:(NSDictionary *)dic

モデルの実際の変換処理を書きます。ここでは、上のarticleを例に実装してみましょう。

- (id)transformWithDictionary:(NSDictionary *)dic
{
    NSArray<NSString *> *keys = dic.allKeys;

    // Realm+JSON でリレーション以外の値を埋める。ここは別クラスで実装しておく。
    Article *article = [[Article alloc] initWithJSONDictionary:dic];

    // "comment_ids"のkeyがあれば、リレーションを作成する
    if ([keys containsObject:@"comment_ids"]) {
        for (NSString *commentID in dic[@"comment_ids"]) {
            // コメントモデルある前提のコード。
            Comment *comment = [Comment objectForPrimaryKey:@([commentID integerValue])];

            if (comment) {
                [article addObject:comment];
            }
        }
    }

    return article;
}

仮に、これを CommentTransformerとすると以下のようにして使えます。

[[[CommentTransformer alloc] init] transformWithDictionary:dic];

これでリレーションが貼れるようになったかと思います。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2