RubyCocoaを極めるプロジェクト中でtwitterクライアントを作るという話が出てたので、正月休み中にみんなでいじって遊べる程度に動くものを作ってしまおうと目下がりがり書いてる最中なのですが、なかなか楽しいね、RubyCocoa。

e84fa15a.png

CoreDataが素敵

折角なのでCoreDataを活用してやろうと、HMDT本やリファレンスと格闘してました。CoreDataってなんぞ?ってレベルからのスタートだったので結構苦労したのだけども、CoreDataってのは要はCocoaアプリ中で簡易DBとO/Rマッパーを使えるようになるフレームワークなんだね。ActiveRecord+pstoreやsqlite、みたいなもんだと言っていいのかな。

で、これが非常に便利。Xcodeのモデリングツールでデータの定義をしておけば、勝手にDBとラッパオブジェクトを作ってくれるのでモデルクラスのとこのコーディングが格段に減る。モデル同士の関連もモデリングツールで作れるし、InterfaceBuilderとの連携でコントローラ部分も自分で作る必要がないので、簡単簡単。RubyCocoaから使う場合はCocoaから使う場合と若干構成が違うので最初躊躇ったけども。自分へのメモの意味でも、Xcode3でRubyCoca-CoreDataアプリを作る際のIBチュートリアル記事をあとで書いとこう。

ちなみに、twitterのデータの読み書きはこんな感じ

まずはデータの新規作成。

# NSManagedObjectのオブジェクトを新しく作ってDBに突っ込む
user = OSX::NSEntityDescription.objc_send("insertNewObjectForEntityForName",
            "User",
            "inManagedObjectContext",
            @managedObjectContext)
user.userId = '11111111'
user.screenName = 'rucotan'                                               
user.name = 'るこたん'

これでるこたんの情報がCoreData経由で使えるようになる。実はこの時点では「るこたんの情報が管理対象になった」だけで、自分でデータの保存処理をするか、CoreDataApplicationテンプレートからプロジェクト作ってるとアプリの正常終了時に自動で保存処理が呼びだされる*1か、そのタイミングで初めてファイルやDBに書き込まれるんだけど、「管理対象になった」時点でアプリ全体で使えるデータになるのでここではあんまり気にしない。

ちなみに、以前はNSManagedObjectのプロパティをいじるのに毎回valueForKeyやsetValue_forKeyを呼び出してたみたいなんだけど、RubyCocoaの改良でラッパオブジェクトを作るようにして、NSManagedObjectをまるでRubyのオブジェクトのように扱えるようになったらしい。軸がぶれてない、素敵*2。この辺がARっぽいとこ。

続いて既にあるデータの取得。

# NSFetchRequestを用意。RDBMSにSELECTクエリを発行するみたいな感じと言えばいいかな。
request = OSX::NSFetchRequest.alloc.init

# モデルを設定。SELECT文のFROMを指定するのに相当すると理解。
entity = OSX::NSEntityDescription.entityForName_inManagedObjectContext('User', @managedObjectContext)
request.setEntity(entity)

# 述語を設定。SELECT文のWHERE句相当、かな。
predicate = OSX::NSPredicate.predicateWithFormat('screenName == %@', 'rucotan')
request.setPredicate(predicate)

error = OSX::OCObject.new
users = @managedObjectContext.executeFetchRequest_error(request, error)

これで「screenNameがrucotanであるUserのリスト」を取得できる。NSFetchRequestとかNSPredicateってのが要はDBハンドラにプリペアードクエリを渡すのと手順は大して変わらないので、日頃DBを使うアプリに慣れてると違和感ないですね。注意点としては、executeFetchRequestの返り値はOSX::NSCFArrayなので、users.empty?とかusers.firstとかやると「そんなメッセージ、わたしが受け付けるとでも思ってるの!?この愚民は言葉もまともに話(ry」と怒られてしまう。Rubyで使うときは最初にto_aしておいた方が楽かも。

これだけだとRubyのARやPerlのClass::DBIに慣れきってる身としてはかったるくてしょうがないんだけど、Xcode上のモデリングツールで受信要求テンプレートというのを作ることができて、それを使うとNSFetchRequestの生成が大分楽になる。

variables = OSX::NSMutableDictionary.dictionary # 述語に渡すパラメータ
variables['screenName'] = 'rucotan'
request = @managedObjectModel.fetchRequestFromTemplateWithName_substitutionVariables('template_name', variables)
error = OSX::OCObject.new
users = @managedObjectContext.executeFetchRequest_error(request, error)

ちなみに、Xcode上で受信要求テンプレートを作る際には述語ビルダというのが使えて、複雑なリクエストでもiTunesやMailのスマートフォルダを作る感覚で述語を生成できてしまうので非常に簡単。だと思われる。いや、まだ使ったことないの。

キーバリューコーディング

に、ついても書こうと思ったんだけど、そろそろ長くなってきたのでまたの機会に。

仮名のRuchettaについて

Rubyの「る」とCocoaの「こ」がつくものがいいなあと考えて真っ先に浮んだのが「ルッコラ」だったんだけど、rucolaって開発環境があるのね、RubyCocoaの。ので、同じくルッコラを意味するイタリア語の「Ruchetta」にしてみた(安易)。ちゃんとr(uby)とc(ocoa)とt(witter)が入ったし、「ついった」と「るけった」で語感的にも悪くないかなと思ったんだけどどうだろう。みんなでいじれるようになったら名前も新しく考えてもらってもいいかな。

先を越された

これを書いてる最中に夏ライオン(OSXのtwitterクライアント)αリリースのお知らせが…。UIかっこいいなぁ。参考にさせてもらおう。

追記

夏ライオン見易くてなかなか良かった。自分でtwitterクライアント作ってる最中なのに当面夏ライオンユーザになりそうな予感。

*1:未確認。アプリ終了時に保存されるのは確かなんだけど、それがどこから何を呼び出してるのか実はわかってない。あとでちゃんと見る。

*2:そういえば絶望先生2期って今クールでしたっけ?