RubyMotion で CoreData が使えることは確認できた。
ただ、CoreData のエンティティ定義をコードで書くのは結構シンドイ。 NSManagedObjectContext の初期化やデータの操作を含めると、CoreData だけでかなりのコードを書くことになる。 正直、CoreData のラッパーを使ったほうがいい。
CoreData のラッパーで良さそうなのが、『MotionData』っていう gem。
Ruby の 有名 ORM 『DataMapper』風に定義できる。
MotionData は Bundler を使ってインストールできる。Gemfile に
gem 'motion_data', github:'alloy/MotionData'
を追加して bundle install 実行するだけ。 MotionData は RubyGems.org で公開されていないから、Github からダウンロードしないといけない。
前回作成した CoreData サンプルを、MotionData を使って書き変えてみたのがこちら。
# coding: utf-8 class AppDelegate def application(application, didFinishLaunchingWithOptions:launchOptions) # CoreData を初期化 path = File.join(NSHomeDirectory(), 'Documents', 'Guestbook.sqlite') MotionData.setupCoreDataStackWithSQLiteStore(path) nav = UINavigationController.alloc.initWithRootViewController(MasterController.alloc.init) @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds) @window.rootViewController = nav @window.makeKeyAndVisible true end end # MotionData::ManagedObject を使えば # DataMapper みたいにモデルを定義できる class Entry < MotionData::ManagedObject property :title, String property :creation_date, Time end class MasterController < UITableViewController def viewDidLoad super navigationItem.title = 'Guestbook' navigationItem.leftBarButtonItem = editButtonItem navigationItem.rightBarButtonItem = UIBarButtonItem.alloc.initWithBarButtonSystemItem( UIBarButtonSystemItemAdd, target:self, action:'add_entry' ) end def save MotionData::Context.main.saveChanges MotionData::Context.root.saveChanges @entries = nil end def add_entry # 追加 Entry.new.tap do |entry| entry.title = 'foo' entry.creation_date = NSDate.date end save view.reloadData end # SQLite に保存したデータを取得 def entries # 日付降順に並び替える @entries ||= Entry.all.sortBy(:creation_date, ascending:false).to_a end def tableView(tableView, numberOfRowsInSection:section) entries.size end CellID = 'CellIdentifier' def tableView(tableView, cellForRowAtIndexPath:indexPath) cell = tableView.dequeueReusableCellWithIdentifier(CellID) || UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:CellID) entry = entries[indexPath.row] @date_formatter ||= NSDateFormatter.alloc.init.tap do |df| df.timeStyle = NSDateFormatterMediumStyle df.dateStyle = NSDateFormatterMediumStyle end cell.textLabel.text = @date_formatter.stringFromDate(entry.creation_date) cell end def tableView(tableView, editingStyleForRowAtIndexPath:indexPath) UITableViewCellEditingStyleDelete end def tableView(tableView, commitEditingStyle:editingStyle, forRowAtIndexPath:indexPath) entry = entries[indexPath.row] # 削除 MotionData::Context.main.deleteObject(entry) save tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation:UITableViewRowAnimationFade) end end
エンティティの定義や NSManagedObjectContext の初期化といった 面倒事を MotionData がやってくれるから、コードがスッキリした。