先日 RubyMotion で CoreData を使うために試した MotionDataWrapper、 ソースコードを見たらシンプルな実装で難しいことやっていなかった。
Xcode の Data Modeler で作成したエンティティ定義を読み込むけど、 それは CoreData.framework が提供している機能を呼び出しているだけ。
これなら MotionDataWrapper 使わず、RubyMotion で直に書けそう。 実際に試してみた。
まず Xcode で Empty プロジェクトを作成。
次に Data Modelファイルを作成。ファイルの保存先は resources 直下で、 ファイル名はとりあえずデフォルトの Model のままにしておく。
エンティティを定義したら Xcode での作業は終了。
RubyMotion で Data Model ファイルを使うサンプルを作成。
# coding: utf-8 class Task < NSManagedObject end class TasksViewController < UITableViewController def viewDidLoad super self.navigationItem.title = "Tasks" self.navigationItem.rightBarButtonItem = UIBarButtonItem.alloc.initWithBarButtonSystemItem( UIBarButtonSystemItemAdd, target: self, action: "add_task" ) self.navigationItem.leftBarButtonItem = self.editButtonItem end def tableView(tableView, numberOfRowsInSection:section) self.tasks.size end def tableView(tableView, cellForRowAtIndexPath:indexPath) task = self.tasks[indexPath.row] cell = tableView.dequeueReusableCellWithIdentifier("Cell") if cell == nil cell = UITableViewCell.alloc.initWithStyle( UITableViewCellStyleDefault, reuseIdentifier:"Cell" ) end cell.textLabel.text = task.title cell end def tableView(tableView, commitEditingStyle:editingStyle, forRowAtIndexPath:indexPath) if editingStyle == UITableViewCellEditingStyleDelete task = self.tasks[indexPath.row] delete_task(task) tableView.deleteRowsAtIndexPaths( [indexPath], withRowAnimation:UITableViewRowAnimationFade ) end end def tasks @tasks ||= begin request = NSFetchRequest.fetchRequestWithEntityName("Task") sortDescriptor = NSSortDescriptor.sortDescriptorWithKey("createdAt", ascending:true) request.sortDescriptors = [sortDescriptor] error = Pointer.new(:object) results = AppDelegate.sharedDelegate.managedObjectContext.executeFetchRequest(request, error:error) results end end def add_task task = NSEntityDescription.insertNewObjectForEntityForName( "Task", inManagedObjectContext:AppDelegate.sharedDelegate.managedObjectContext ) task.title = "test" task.createdAt = NSDate.date AppDelegate.sharedDelegate.saveContext @tasks = nil self.tableView.reloadData end def delete_task(task) AppDelegate.sharedDelegate.managedObjectContext.deleteObject(task) AppDelegate.sharedDelegate.saveContext @tasks = nil end end class AppDelegate def self.sharedDelegate UIApplication.sharedApplication.delegate end def application(application, didFinishLaunchingWithOptions:launchOptions) navi = UINavigationController.alloc.initWithRootViewController( TasksViewController.alloc.init ) @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds) @window.rootViewController = navi @window.makeKeyAndVisible true end def applicationWillTerminate(application) self.saveContext end def saveContext error = Pointer.new(:object) managedObjectContext = self.managedObjectContext if managedObjectContext != nil if managedObjectContext.hasChanges and !managedObjectContext.save(error) NSLog("Unresolved error #{error[0]}, #{error[0].userInfo}") abort() end end end def managedObjectContext @managedObjectContext ||= begin coordinator = self.persistentStoreCoordinator if coordinator != nil managedObjectContext = NSManagedObjectContext.alloc.init managedObjectContext.setPersistentStoreCoordinator(coordinator) managedObjectContext else nil end end end def managedObjectModel @managedObjectModel ||= begin modelURL = NSBundle.mainBundle.URLForResource("Model", withExtension:"momd") NSManagedObjectModel.alloc.initWithContentsOfURL(modelURL) end end def persistentStoreCoordinator @persistentStoreCoordinator ||= begin storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("CoreDataSample2.sqlite") error = Pointer.new(:object) persistentStoreCoordinator = NSPersistentStoreCoordinator.alloc.initWithManagedObjectModel(self.managedObjectModel) unless persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration:nil, URL:storeURL, options:nil, error:error) NSLog("Unresolved error #{error[0]}, #{error[0].userInfo}") abort() end persistentStoreCoordinator end end def applicationDocumentsDirectory NSFileManager.defaultManager.URLsForDirectory( NSDocumentDirectory, inDomains:NSUserDomainMask ).last end end
CoreData の初期化部分は、 CoreData を使う iOS アプリのプロジェクトを Xcode で新規作成したとき生成されるソースコードと、 やってることはほぼ同じ。
RubyMotion で直に書けはしたけど、記述量が多くて毎回これ書こうとは思えない。 CoreData 部分をモジュール化して再利用するか、やっぱりライブラリ使うだろうな。