どーも。寺坂です
最近、CoreDataのテストを書いている時に、
ローカルのファイルを汚したくないなー
と思ったので、Swiftで メモリ上でデータ管理を行う方法 を紹介します。
前提: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 } }