#author("2016-10-18T14:55:39+09:00","default:wikiwriter","wikiwriter") #author("2017-01-16T14:29:22+09:00","default:wikiwriter","wikiwriter") *目次 [#e86b220c] #contents *プロジェクトの作成 [#z2dcfcca] -プロジェクトの新規作成で、Empty Projectを選ばないとだめ。 -既存プロジェクトに追加する方法に関しては以下を参照のこと。 --[[Adding Core Data Existing iPhone Projects « Wires Are Obsolete:http://wiresareobsolete.com/wordpress/2009/12/adding-core-data-existing-iphone-projects/]] --[[iphone - Adding Core Data to existing project in XCode 4 - Stack Overflow:http://stackoverflow.com/questions/6821719/adding-core-data-to-existing-project-in-xcode-4]] *構成要素 [#d1072375] **Persistent store [#vbafd56c] -バックエンド。SQLite3とか。 **Data model [#vbbe47c1] -テーブルスキーマ。 -Xcodeのデータモデルエディタで作る。.xcdatamodeldに保存される。 -Object-CのクラスとしてはNSManagedObjectModelに対応。 #pre{{ - (NSManagedObjectModel *)managedObjectModel { if (managedObjectModel_ != nil) { return managedObjectModel_; } NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"CoreData" ofType:@"momd"]; NSURL *modelURL = [NSURL fileURLWithPath:modelPath]; managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return managedObjectModel_; } }} **Persistent store coordinator[#sebef938] -Persistent storeとData modelを使ってManaged objectとを作り出す。 #pre{{ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (persistentStoreCoordinator_ != nil) { return persistentStoreCoordinator_; } NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"CoreData.sqlite"]]; NSError *error = nil; persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return persistentStoreCoordinator_; } }} -Managed object contextで管理される。 **Managed object and managed object context[#fbd24cdf] -Managed ObjectsはDTO(みたいなもんか)。 -Key-Value Coding対応。 NSDate* t = [managedObject valueForKey:@"updateDate"] -Managed Object ContextはManaged Objectsを管理する。Persistent store coordinatorを使う。 **Fetch requerst [#xd1bab7c] -条件を駆使してオブジェクトを取り出す。 *データモデルエディタ [#h63a8f51] **起動方法 [#y43d24aa] .xcdatamodelをクリックすると起動する。 **エンティティ [#s15a1061] -テーブルに該当。 -左上のペインで追加削除できる。 **プロパティ [#d76f1b07] -テーブルのカラムに該当。 -選択されたテーブルのカラムが一覧表示される。 **属性 [#db5d984a] -カラムの型に該当。 -選択されたカラムの属性が表示される。 *Fetch Results Controller [#wd025de2] -NManagedObjectsを管理されているオブジェクトを表示したり削除したりするのを助けるcontroller。 -イベントが発生するとdelegateメソッドが呼び出されるのでそこでビューを更新したりする。 *関連 [#pfc3c107] -To-Manyの場合もTo-Oneの場合も逆関連を設定しておいたほうが便利。 -どちらか一方で関連づけるともう一方の関連も動的にメンテナンスされる。 -あるオブジェクトに関連づけられた子オブジェクトの集合からNSFetchedResultsControllerを生成したい場合、親オブジェクトのIDをNSPredicateに指定すると良い。 -例えば本棚に多数の本が関連づけられているとして、以下のようにNSPredicateを指定する。book.shelfは本から本棚への逆関連。Shelfはbooksとしてbookを所有為ている場合(%@"でobjectIDによる絞り込みが実現)。 #pre{{ let fetchRequest = NSFetchRequest() let entity = NSEntityDescription.entityForName("Book", inManagedObjectContext: managedObjectContext) fetchRequest.entity = entity let pred = NSPredicate(format: "shelf=%@", argumentArray: [shelf]) fetchRequest.predicate = pred }} *Tips [#k8ff30ec] **transientプロパティの使いどころって? [#i332cdfd] -NSManagedObjectObjectを継承したモデルクラスで一時的なプロパティに対して、transientプロパティを使うらしい。Undoサポートや初期化処理なんかを考えない場合通常の@propertyを使っても問題なさそう。[[core data - NSManagedObject: Should I use transient or a regular @property? - Stack Overflow:http://stackoverflow.com/questions/8690831/nsmanagedobject-should-i-use-transient-or-a-regular-property]] **新規オブジェクトのキャンセル処理 [#z820f6af] -保存ボタンを押した際に、insertNewObjectForEntityForNameを呼び出す方法 --[[iphone - Cancel New CoreData Object? - Stack Overflow:http://stackoverflow.com/questions/13344327/cancel-new-coredata-object]] --NSManagedObjectが直前まで作られない方法。しかしNSManagedObjectを使った検証や、NSManagedObjectを使った初期化処理がおこなえない欠点あり。 -rollback()を使う。 -キャンセル時にdeleteObjectする。[[ちょっとだけ本格的なiPhone Core Dataアプリケーションへの拡張:http://konton.ninpou.jp/program/cocoa/coredata/firstcoredata.html]]…。deleteするのが一番簡単? -CoreDataBooks。[[CoreDataBooks:https://developer.apple.com/library/ios/samplecode/CoreDataBooks/Introduction/Intro.html]]。子コンテキストを作成し追加処理を分離。 #pre{{ NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [addingContext setParentContext:[self.fetchedResultsController managedObjectContext]]; }} **初期データの投入 [#d2ae8e56] -[[ios - What is the best way fill in database core data at first launch - Stack Overflow:http://stackoverflow.com/questions/27917913/what-is-the-best-way-fill-in-database-core-data-at-first-launch]] -例えばNSUserDefaultsなどに初回起動かどうかを覚えさせておき、初回の場合は初期データを投入する処理を呼び出す。 *トラブルシューティング [#se92d421] **Xcode 8 + Swift 3での不具合 [#e9d6880e] -モデルクラスの生成はxcdatamodeldを選択して、Editor > Create NSManagedObjectから実行。 -モデル名+CoreDataClass.swiftに不完全なimport文が追加されてエラーとなるのでそれは削除する。