Swiftで遊ぼう! - 599 - Multiple Managed Object Contextsチュートリアル 4
- Swiftで遊ぼう!の前書き-> Life-LOG OtherSide
- Swift2.1 & Xcode7.1対応の日本語版アップルチュートリアル!
- Table View実装チュートリアルをXcode7.2.1で解説
- Core Data シンプルチュートリアル
- 私の本業、オフィシャルなブログ-> Life-LOG
オリジナルアプリに近いアプリのチュートリアに取り組んでいます。
今回のチュートリアルは少し複雑なので、ある程度できあがっているスターター・プロジェクトが用意されています。
ダウンロードしてプロジェクト・ナビゲータを開くと、数々のファイルが並んでいます。まず、CoreDataStack.swiftファイルと、関連するCoreDataSeedフォルダーに存在するファイルの関連性をみていきます。
まずCoreDataStack.swiftファイルのコードをみます。まず全体のコードを眺めてみても何となく理解できるような気がします。やっぱり完全な初心者から脱却できているのかもしれません。チュートリアルで注目している部分から取りかかります。
import CoreData class CoreDataStack { let modelName = "SurfJournalModel" let seedName = "SurfJournalDatabase" lazy var applicationDocumentsDirectory: NSURL = { let urls = NSFileManager.defaultManager().URLsForDirectory( .DocumentDirectory, inDomains: .UserDomainMask) return urls[urls.count-1] }() lazy var managedObjectModel: NSManagedObjectModel = { let modelURL = NSBundle.mainBundle() .URLForResource(self.modelName, withExtension: "momd")! return NSManagedObjectModel(contentsOfURL: modelURL)! }() lazy var psc: NSPersistentStoreCoordinator = { let coordinator = NSPersistentStoreCoordinator( managedObjectModel: self.managedObjectModel) let url = self.applicationDocumentsDirectory .URLByAppendingPathComponent(self.seedName + ".sqlite") // 1 let bundle = NSBundle.mainBundle() let seededDatabaseURL = bundle .URLForResource(self.seedName, withExtension: "sqlite")! // 2 let didCopyDatabase: Bool do { try NSFileManager.defaultManager() .copyItemAtURL(seededDatabaseURL, toURL: url) didCopyDatabase = true } catch { didCopyDatabase = false } // 3 if didCopyDatabase { // 4 let seededSHMURL = bundle .URLForResource(self.seedName, withExtension: "sqlite-shm")! let shmURL = self.applicationDocumentsDirectory .URLByAppendingPathComponent(self.seedName + ".sqlite-shm") do { try NSFileManager.defaultManager() .copyItemAtURL(seededSHMURL, toURL: shmURL) } catch { let nserror = error as NSError print("Error: \(nserror.localizedDescription)") abort() } // 5 let seededWALURL = bundle .URLForResource(self.seedName, withExtension: "sqlite-wal")! let walURL = self.applicationDocumentsDirectory .URLByAppendingPathComponent(self.seedName + ".sqlite-wal") do { try NSFileManager.defaultManager() .copyItemAtURL(seededWALURL, toURL: walURL) } catch { let nserror = error as NSError print("Error: \(nserror.localizedDescription)") abort() } print("Seeded Core Data") } // 6 do { try coordinator.addPersistentStoreWithType( NSSQLiteStoreType, configuration: nil, URL: url, options: nil) } catch { //7 let nserror = error as NSError print("Error: \(nserror.localizedDescription)") abort() } return coordinator }() lazy var context: NSManagedObjectContext = { var managedObjectContext = NSManagedObjectContext( concurrencyType: .MainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = self.psc return managedObjectContext }() func saveContext () { if context.hasChanges { do { try context.save() } catch { let nserror = error as NSError print("Error: \(nserror.localizedDescription)") abort() } } } }
まずこの長ったらしいコードの中でナンバリングされている部分から取りかかります。
// 1 let bundle = NSBundle.mainBundle() let seededDatabaseURL = bundle .URLForResource(self.seedName, withExtension: "sqlite")! // 2 let didCopyDatabase: Bool do { try NSFileManager.defaultManager() .copyItemAtURL(seededDatabaseURL, toURL: url) didCopyDatabase = true } catch { didCopyDatabase = false }
- 「NSBundle.mainBundle()」は、何度も何度も繰り返して勉強しているので、やっと自然に頭に入ってくるようになりました。まだの人はシングルトン・パターンのページを読みましょう。NSBundleクラスも復習したので、まだの人はこのページを確認しましょう。まずこのデータベースは、立ち上げた時に前もってデータを持たせるステップです。「URLForResource」メソッドは、プロジェクト内に存在するファイルの位置を「NSURL?」クラスで返します。パラメーターで、String型の名前と拡張子を受け取ります。ここで「self.seedName」になっていますが、コードの前半部分で定義されています(ハードコーティング)。「seededDatabaseURL」には、ファイルの位置情報がNSURLクラスとして保持されます。
- 「didCopyDatabase」はBoolean型の定数です。私がコーディングするなら、変数にしてしまいそうですが、ベテランプログラマーは、何の躊躇いもなく定数宣言しています。確かに、この定数に値を入れるタイミングは1度だけでいいので変数にする必要もありません。そして、NSFileManagerクラスが出てきます。これも復習したんですが、新しいメソッドが出てきています。「copyItemAtURL」は、2つの引数を取ります。どちらもNSURLクラスのオブジェクトを指定します。最初の引数はコピー元で、2番目の引数はコピー先です。コピー先にオブジェクトが存在すれば、このメソッドはerrorを投げる(throws)タイプなので、必ず「try」が要ります。コピーに成功すれば、定数「didCopyDatabase」を「true」にして、失敗すれば「false」にして後の処理に利用します。
copyItemAtURLメソッドの2つめの引数「url」を明日考察します。