如何在其他 NSManagedObjectContext 中插入 NSManagedObject?

Posted

技术标签:

【中文标题】如何在其他 NSManagedObjectContext 中插入 NSManagedObject?【英文标题】:How to insert NSManagedObject in other NSManagedObjectContext? 【发布时间】:2013-08-07 10:35:58 【问题描述】:

我正在从服务器获取数据并将它们转换为 NSManagedObject 对象数组。 该数组用于显示表格。

如何在持久存储中插入第一个元素数组peoples

- (void)viewDidLoad

     [self loadData];
     [self insertFirstPeople];


- (NSManagedObjectContext *)managedObjectContext

    if(!_managedObjectContext) _managedObjectContext = [NSManagedObjectContext MR_context];
    return _managedObjectContext;


- (void)loadData

    ... 
       Network Request
    ...
    peoples = [NSMutableArray array];
    for (NSDictionary *item in items)
    
        People *people = [Podcast MR_createInContext:self.managedObjectContext];
        people.name = [item valueForKeyPath:@"im:name.label"];
        [peoples addObject:people];
    


-(void)insertFirstPeople

    People *people = peoples[0];
    NSManagedObjectContext *moc = [NSManagedObjectContext MR_defaultContext];
    [moc insertObject:people]
    [moc MR_saveToPersistentStoreAndWait];

错误:

An NSManagedObject may only be in (or observed by) a single NSManagedObjectContext.

【问题讨论】:

您是否打算使用两个不同的托管对象上下文?您真的只想要在默认上下文中插入的 first People 对象吗?在后台上下文中创建的其他对象呢? 是的。我想使用两个上下文。第一个只建表,第二个保存持久化存储 好的,但是你想将 all People 对象保存到持久存储中还是只保存 first 对象? 只有第一个对象 这可能很难/不可能。您可以将对象从一个上下文转移到另一个上下文(例如使用[people MR_inContext:[NSManagedObjectContext MR_defaultContext]]),但这仅在对象已保存时才有效。保存背景上下文将保存 all 对象。更准确地说,由于背景上下文是默认上下文的子上下文,保存背景上下文意味着所有插入的对象都插入到默认上下文中。 【参考方案1】:

我自己已经找到了解决问题的方法。

-(void)insertFirstPeople

    People *people = peoples[0];
    CoreDataHelper *helper = [[CoreDataHelper alloc] init];
    NSManagerObjectContext *context = [NSManagedObjectContext MR_defaultContext];
    [helper saveObject:people toContext:context];
    [context MR_saveOnlySelfAndWait];

CoreDataHelper.h

#import <Foundation/Foundation.h>


@interface CoreDataHelper : NSObject

    NSMutableDictionary* _lookup;

@property(nonatomic, retain) NSMutableDictionary *lookup;

-(void)saveFrom:(NSManagedObjectContext *)current to:(NSManagedObjectContext *)parent;

- (NSManagedObject *)saveObject:(NSManagedObject *)object toContext:(NSManagedObjectContext *)moc;

- (NSManagedObject*)copyObject:(NSManagedObject*)object
                     toContext:(NSManagedObjectContext*)moc
                        parent:(NSString*)parentEntity;
@end

CoreDataHelper.m

#import "CoreDataHelper.h"

@implementation CoreDataHelper

@synthesize lookup = _lookup;

-(void)saveFrom:(NSManagedObjectContext *)current to:(NSManagedObjectContext *)parent

    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
          [dnc addObserverForName:NSManagedObjectContextDidSaveNotification
                           object:current queue:nil
                       usingBlock:^(NSNotification *notification)
         
           [parent mergeChangesFromContextDidSaveNotification:notification];
         ];
        NSError *error;
        if (![current save:&error])
          
              NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
          

          [dnc removeObserver:self
                         name:NSManagedObjectContextDidSaveNotification
                       object:current];



- (NSManagedObject *)saveObject:(NSManagedObject *)object toContext:(NSManagedObjectContext *)moc 
    NSUndoManager *docUndoMgr = [moc undoManager];
    [docUndoMgr beginUndoGrouping];

    NSManagedObject *object2 = [self copyObject:object toContext:moc parent:nil];

    [moc processPendingChanges];
    [docUndoMgr endUndoGrouping];
    return object2;


- (NSManagedObject *)copyObject:(NSManagedObject *)object
                      toContext:(NSManagedObjectContext *)moc
                         parent:(NSString *)parentEntity; 
    NSError *error = nil;
    NSString *entityName = [[object entity] name];
    NSManagedObject *newObject = nil;
    if ([moc objectRegisteredForID:object.objectID])
        newObject = [moc objectWithID:object.objectID];
    else
        newObject = [NSEntityDescription
                insertNewObjectForEntityForName:entityName
                         inManagedObjectContext:moc];


    if (![moc save:&error])
    
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    

    [[self lookup] setObject:newObject forKey:[object objectID]];

    NSArray *attKeys = [[[object entity] attributesByName] allKeys];
    NSDictionary *attributes = [object dictionaryWithValuesForKeys:attKeys];

    [newObject setValuesForKeysWithDictionary:attributes];

    id oldDestObject = nil;
    id temp = nil;
    NSDictionary *relationships = [[object entity] relationshipsByName];
    for (NSString *key in [relationships allKeys]) 

        NSRelationshipDescription *desc = [relationships valueForKey:key];
        NSString *destEntityName = [[desc destinationEntity] name];
        if ([destEntityName isEqualToString:parentEntity]) continue;

        if ([desc isToMany]) 

            NSMutableSet *newDestSet = [NSMutableSet set];

            for (oldDestObject in [object valueForKey:key]) 
                temp = [[self lookup] objectForKey:[oldDestObject objectID]];
                if (!temp) 
                    temp = [self copyObject:oldDestObject
                                  toContext:moc
                                     parent:entityName];
                
                [newDestSet addObject:temp];
            

            [newObject setValue:newDestSet forKey:key];

         else 
            oldDestObject = [object valueForKey:key];
            if (!oldDestObject) continue;

            temp = [[self lookup] objectForKey:[oldDestObject objectID]];
            if (!temp && ![destEntityName isEqualToString:parentEntity]) 
                temp = [self copyObject:oldDestObject
                              toContext:moc
                                 parent:entityName];
            

            [newObject setValue:temp forKey:key];
        
    

    return newObject;


@end

【讨论】:

以上是关于如何在其他 NSManagedObjectContext 中插入 NSManagedObject?的主要内容,如果未能解决你的问题,请参考以下文章

跳过核心数据迁移

NSFetchedResultsController、NSManagedObjectContextDidSaveNotification 和 MagicalRecord 的舞蹈

IOS CoreData,使用哪个 NSManagedObjectContextConcurrencyType,为啥?

最佳实践 - iOS 中的 NSManagedObjectContextObjectsDidChangeNotification

从另一个 NSManagedObjectContext 获取 NSManagedObject(引用相同的 NSPersistentStoreCoordinator)

当用户在其他地方交互时如何关闭 Snackbar?