NSManagedObjectオブジェクトをdeep copyする方法
NSManagedObjectオブジェクトをdeep copyする方法を考えてみた。NSManagedObjectはNSCopyingプロトコルに適合していない。AttributeやRelationshipを個別にチェックしてコピーしていく方法が無難だろうと思う。*1*2
具体的な手順としては次のようになる。
- コピー対象のNSManagedObjectオブジェクト(以下では「コピー元オブジェクト」と呼ぶ)と同じエンティティのNSManagedObjectオブジェクト(以下では「コピー先オブジェクト」と呼ぶ)を新規作成する。
- コピー元オブジェクトのAttributeを取得し、それぞれのコピーをコピー先オブジェクトのAttributeとして設定する。
- コピー元オブジェクトのRelationshipを取得し、それぞれのRelationshipに対し必要に応じて同エンティティのコピーを作成して、コピー先オブジェクトのRelationshipとして設定する。
この処理に対応するコードは次のようになる。
// 呼び出し元で保存する。 - (NSManagedObject *)copyCompanyObjectWithObjectID:(NSManagedObjectID *)objID context:(NSManagedObjectContext *)context { if (objID == nil) { NSLog(@"Failed to copy company object. Object ID is nil."); return nil; } if (context == nil) { NSLog(@"Failed to copy company object. Context is nil."); return nil; } // 1. // コピー元オブジェクトと同じエンティティのNSManagedObjectオブジェクトを新規作成する。 // fetchCompanyObjectWithIdentifier:context および insertNewCompanyObjectWithContext:の // 実装はここでは省略する。 NSManagedObject *orgObj = [self fetchCompanyObjectWithIdentifier:objID context:context]; NSManagedObject *newObj = [self insertNewCompanyObjectWithContext:context]; // 2. // コピー元オブジェクトのAttributeを取得し、 // それらのコピーをコピー先オブジェクトのAttributeとして設定する。 NSDictionary *attrDict = [[orgObj entity] attributesByName]; for (NSString *key in [attrDict allKeys]) { id value = [orgObj valueForKey:key]; [newObj setValue:value forKey:key]; } // 3. // コピー元オブジェクトのRelationshipを取得し、 // それぞれのRelationshipに対し必要に応じて同エンティティのコピーを作成して、 // コピー先オブジェクトのRelationshipとして設定する。 NSDictionary *relDict = [[orgObj entity] relationshipsByName]; for (NSString *key in [relDict allKeys]) { // ここでは例としてOrdered To-many Relationshipのひとつをコピーしている。 if ([key isEqualToString:@"employees"]) { NSOrderedSet *employeeSet = [orgObj valueForKey:key]; for (NSInteger i = 0; i < employeeSet.count; i++) { // copyEmployeeObjectWithObjectID:context:の実装はここでは省略するが、 // copyCompanyObjectWithObjectID:context:と同様に定義しておけばよい。 NSManagedObject *orgEmployeeObj = employeeSet[i]; NSManagedObject *newEmployeeObj = [self copyEmployeeObjectWithObjectID:[orgEmployeeObj objectID] context:context]; [newObj addEmployeesObject:newEmployeeObj]; } } } return newObj; }