Эти ответы меня очень близко подобрали, хотя, похоже, в них есть некоторые недостатки:
Во-первых, я последовал совету Z S и сделал его категорией на NSManagedObject, мне это показалось немного чище.
Во-вторых, мой граф объектов содержит отношения «к одному», поэтому я начал с примера levous, но обратите внимание, что пример levous не клонирует объект в случае отношения «к одному». Это вызовет сбой (попытка сохранить NSMO из одного контекста в другом контексте). Я обратился к этому в приведенном ниже примере.
В-третьих, я предоставил кеш уже клонированных объектов, это предотвращает двойное клонирование объектов и, следовательно, дублирование в новом графе объектов, а также предотвращает циклы.
В-четвертых, я добавил черный список (список типов сущностей, которые нельзя клонировать). Я сделал это частично, чтобы решить один недостаток моего окончательного решения, о котором я расскажу ниже.
ПРИМЕЧАНИЕ: если вы используете то, что я понимаю, как лучшую практику CoreData, всегда обеспечивая обратные отношения, то это, скорее всего, клонирует все объекты, которые имеют отношение к объекту, который вы хотите клонировать. Если вы используете инверсии и у вас есть единственный корневой объект, который знает обо всех других объектах, то вы, скорее всего, клонируете все это целиком. Моим решением было добавить черный список и передать тип Entity, который, как я знал, был родительским для одного из объектов, которые я хотел клонировать. Похоже, это работает для меня. :)
Удачного клонирования!
// NSManagedObject+Clone.h
#import <CoreData/CoreData.h>
@interface NSManagedObject (Clone)
- (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSArray *)namesOfEntitiesToExclude;
@end
// NSManagedObject+Clone.m
#import "NSManagedObject+Clone.h"
@implementation NSManagedObject (Clone)
- (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary *)alreadyCopied exludeEntities:(NSArray *)namesOfEntitiesToExclude {
NSString *entityName = [[self entity] name];
if ([namesOfEntitiesToExclude containsObject:entityName]) {
return nil;
}
NSManagedObject *cloned = [alreadyCopied objectForKey:[self objectID]];
if (cloned != nil) {
return cloned;
}
//create new object in data store
cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
[alreadyCopied setObject:cloned forKey:[self objectID]];
//loop through all attributes and assign then to the clone
NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName];
for (NSString *attr in attributes) {
[cloned setValue:[self valueForKey:attr] forKey:attr];
}
//Loop through all relationships, and clone them.
NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName];
for (NSString *relName in [relationships allKeys]){
NSRelationshipDescription *rel = [relationships objectForKey:relName];
NSString *keyName = rel.name;
if ([rel isToMany]) {
//get a set of all objects in the relationship
NSMutableSet *sourceSet = [self mutableSetValueForKey:keyName];
NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName];
NSEnumerator *e = [sourceSet objectEnumerator];
NSManagedObject *relatedObject;
while ( relatedObject = [e nextObject]){
//Clone it, and add clone to set
NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude];
[clonedSet addObject:clonedRelatedObject];
}
}else {
NSManagedObject *relatedObject = [self valueForKey:keyName];
if (relatedObject != nil) {
NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude];
[cloned setValue:clonedRelatedObject forKey:keyName];
}
}
}
return cloned;
}
- (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSArray *)namesOfEntitiesToExclude {
return [self cloneInContext:context withCopiedCache:[NSMutableDictionary dictionary] exludeEntities:namesOfEntitiesToExclude];
}
@end
person
Derrick
schedule
30.09.2011