定食屋おろポン

おろしポン酢と青ネギはかけ放題です

NSRailsが面白いことをしていた

サーバサイドとiPhoneアプリの連携をしたくて、Ruby on Railsの勉強中です。優れたFWの勉強が楽しいのは、CocoaRailsも一緒ですね。

Railsでサーバサイドがある程度作れるようになると、iPhone側と連携したくなります。自前でNSURLConnectionをこねくり回すのもいいんですが、まずは適当なFWを探します。

今だと、NSRails*1が有名みたいなのでREADME.mdを読んでいたわけですが、使い方でちょっと気になったところがあったので以下に引用します。

まず、NSRRemoteObjectのサブクラスを宣言します。自分のRailsプロジェクトのモデルと一対一で作るようです。

@interface Post : NSRRemoteObject

@property (nonatomic, strong) NSString *author, *content;
@property (nonatomic, strong) NSDate *createdAt;

@end

宣言したサブクラスを使って通信を行うのが以下。

Post *post = [Post remoteObjectWithID:1 error:&error];

// Update this post remotely
post.content = @"Changed!";
[post remoteUpdate:&error];

// Fetch any latest data for this post
[post remoteFetch:&error];

// Retrieve a collection based on an object - will GET /posts/1/responses.json
NSArray *responses = [Response remoteAllViaObject:post error:&error];

// Async is also available for all commands, with blocks!
[post remoteDestroyAsync: ^(NSError *error) {  if (!error) ... }];

自分で宣言したクラス名とプロパティ名でリクエストURL作るの?ほえ?

これを見る限り、FWは以下の二点を知る必要があります。

  • FWを"使う側のプロジェクト"が宣言した、NSRRemoteObjectサブクラスのプロパティ名
  • NSRRemoteObjectサブクラスのクラス名

一点目は、objc/runtime.hのランタイム関数を使う必要があります。ソースコードを見ると、class_copyPropertyListを使っていました。実装はさほど難しくないです。
class_copyPropertyListで取得できるのは引数で指定したクラスで宣言したプロパティのみで、祖先クラスのプロパティは取得しないのでこういうことが出来るんですね。祖先クラスまで取ってきちゃうとNSObjectのプロパティとかも取得してしまう。
二点目は、NSStringFromClass(self.class)で簡単。

実装がトリッキーで面白いというよりも、「その発想はなかったわ」という感じです。
もしも僕が実装するとしたら、NSRRemoteObjectにmodelNameとかmodelAttributesとかプロパティを作って、

NSRRemoteObject* post;
post = [NSRRemoteObject remoteObjectWithID:1 error:&error];
post.modelName = @"post"
post.modelAttributes = @{@"content" : @"Changed!"};

とするでしょうね。
正直そのほうが素直でよろしいのではないかとは思いますが、こういうのも面白くてよろしい。
勝手にNSプレフィクスを付けちゃうところとか、コーディングスタイルとか、気に喰わないところも多少ありますが発想が面白そうなので、他の箇所のコードも読んでみようかと思います。

*1:http://nsrails.com