どーも。寺坂です
最近、CoreDataのテストを書いている時に、
ローカルのファイルを汚したくないなー
と思ったので、 メモリ上でデータ管理を行う方法 を紹介します。
前提:CoreDataとは
CoreDataは、データを永続化するためのフレームワークの一つです。
多くの場合、SQLiteを利用して使用され、
端末内に.sqliteファイルを作成して、そこにデータを保存します。
このままだと、ファイルが汚れてゴミが残ったり、
読み書きが発生して遅くなりったりするので、
今回は、このCoreDataの保存先を
メモリ上に変更する方法を紹介したいと思います。
※ 使用するコードは、Xcodeでデフォルト生成されるものを元にします。
実装1.NSManagedObjectModel
NSManagedObjectModelは、CoreDataのEntityを定義したものです。
これは .momdで保存されるファイルに書かれているので、
まずはそのファイルパスを取得します。
class CoreDataInMemory {
  let myModuleName = "モジュール名を記述"
  lazy var managedObjectModel: NSManagedObjectModel = {
     let modelURL = NSBundle(forClass: CoreDataInMemory.self).URLForResource(myModuleName, withExtension: "momd")!
     return NSManagedObjectModel(contentsOfURL: self.modelURL)!
     }()
}
実装2.NSPersistentStoreCoordinator
managedObjectModelを呼んで、
NSPersistentStoreCoordinatorを生成します。
ここでNSInMemoryStoreType を指定することによって、
メモリ上で動作するようになります。
参考:CoreData Framework Reference NSPersistentStoreCoordinator Class Reference - Store Types
class CoreDataInMemory {...
    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        var coordinator:NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        if coordinator?.addPersistentStoreWithType( NSInMemoryStoreType, configuration: nil, URL: nil, options: nil, error: nil) == nil {
            coordinator = nil
        }
        return coordinator
        }()
...
}
実装3.NSManagedObjectContext
NSManagedObjectContextの生成。
ここで先ほどのcoordinatorを使用します。
let coordinator = self.persistentStoreCoordinator
managedObjectContext.persistentStoreCoordinator = coordinator
を忘れると動かないので、ご注意を。
class CoreDataInMemory {...
    lazy var managedObjectContext: NSManagedObjectContext? = {
        let coordinator = self.persistentStoreCoordinator
        var managedObjectContext = NSManagedObjectContext()
        managedObjectContext.persistentStoreCoordinator = coordinator
        return managedObjectContext
        }()
...
}
実装4.saveContext()
データ保存はそのままです。
class CoreDataInMemory {...
    func saveContext() {
        var error:NSError? = nil
        managedObjectContext?.save(&error)
        if let e = error {
            log.error( CoreDataError(cause: e).description )
        }
    }
...
}
実装5.解放
nilを入れましょう。
class CoreDataInMemory {...
    func releaseMemory(){
        persistentStoreCoordinator = nil
        managedObjectContext = nil
    }
...
}
まとめ
以下のようなクラスができました。
テストの時はこちらを使うようにすると、
ストレスレステストができますね。
class CoreDataInMemory {
    
    let myModuleName = "モジュール名を記述"
    
    lazy var managedObjecar: NSManagedObjectModel = {
        let modelURL = NSBundle(forClass: CoreDataInMemory.self).URLForResource(myModuleName, withExtension: "momd")!
        return NSManagedObjectModel(contentsOfURL: self.modelURL)!
        }()
    
    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        var coordinator:NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        if coordinator?.addPersistentStoreWithType( NSInMemoryStoreType, configuration: nil, URL: nil, options: nil, error: nil) == nil {
            coordinator = nil
        }
        return coordinator
        }()
    
    
    lazy var managedObjectContext: NSManagedObjectContext? = {
        let coordinator = self.persistentStoreCoordinator
        var managedObjectContext = NSManagedObjectContext()
        managedObjectContext.persistentStoreCoordinator = coordinator
        return managedObjectContext
        }()
    
    
    func saveContext() {
        var error:NSError? = nil
        managedObjectContext?.save(&error)
        if let e = error {
            log.error( CoreDataError(cause: e).description )
        }
    }
    
    func releaseMemory(){
        persistentStoreCoordinator = nil
        managedObjectContext = nil
    }
    
}
