MotionDataWrapper と NSFetchedResultsController を組み合わせる

MotionDataWrapper を使うと、CoreData を ActiveRecord ライクに扱えるため、

# すべてのエントリを配列で取得
all_entries = Entry.all

# 下書きのみを配列で取得
draft_entries = Entry.where("draft = ?", true).all

という風に、簡単にデータを取得できる。

ただ、データが少ない場合はこれでいいけど、データが増えてきたら配列で取得するのは効率悪いんで、 NSFetchedResultsController を使いたい。さてどうしよう?

実は、where や order が返すのは MotionDataWrapper::Relation クラスのインスタンスで、 この MotionDataWrapper::Relation クラスは NSFetchedRequest を継承していたりする。

だから where や order の返り値をそのまま NSFetchedResultsController に渡せば OK。

scope = Entry.where("draft = ?", true)

ctrl = NSFetchedResultsController.alloc.initWithFetchRequest(
  scope,
  managedObjectContext: App.delegate.managedObjectContext,
  sectionNameKeyPath: nil,
  cacheName: nil
)

ソースコードを読めば分かるといえば、それまでなんだけど…。

参考までに、自分の場合 MotionDataWrapper::Relation クラスに fetch メソッドを定義して使っている。

module MotionDataWrapper
  class Relation
    def fetch(options={})
      params = {
        delegate: nil,
        sectionNameKeyPath: nil,
        cacheName: nil,
      }.merge(options)

      ctrl = NSFetchedResultsController.alloc.initWithFetchRequest(
        self,
        managedObjectContext: App.delegate.managedObjectContext,
        sectionNameKeyPath: params[:sectionNameKeyPath],
        cacheName: params[:cacheName]
      )
      ctrl.delegate = params[:delegate]

      error = Pointer.new(:object)
      ctrl.performFetch(error)
      ctrl
    end
  end
end