まず
ツッコミ大歓迎!!
未熟な部分が多いと思うので、ぜひご教授願います。
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];
これでリレーションが貼れるようになったかと思います。