从子上下文分配对象时非法尝试建立关系

Posted

技术标签:

【中文标题】从子上下文分配对象时非法尝试建立关系【英文标题】:Illegal attempt to establish a relationship when assigning object from child context 【发布时间】:2014-06-22 07:19:53 【问题描述】:

我花了几个小时试图解决父子核心数据模型的问题。但是,让我们从头开始。我有主要上下文和以.parentContext 作为主要上下文的子上下文。

- (NSManagedObjectContext *)mainContext 
    if (!_mainContext) 
        _mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_mainContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
    
    return _mainContext;


- (NSManagedObjectContext *)childContext 
    if (!_childContext) 
        _childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_childContext setParentContext:self.mainContext];
    
    return _childContext;

接下来我在不同的上下文中创建两个对象。

Entity2 *entity2 = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Entity2 class]) 
                                                 inManagedObjectContext:_stack.childContext];

Entity1 *entity1 = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Entity1 class])
                                                 inManagedObjectContext:_stack.mainContext];
entity1.arg1 = @"ABC";
entity1.arg2 = @"DEF";

这里一切正常。

然后我想将一个对象添加到另一个对象的关系中,无论我尝试将entity1 添加到entity2 还是反之亦然。

[entity1 setEntity2:entity2];

在Multi-Context Core Data | Cocoanetics 的文章中,我读到我应该使用保存操作执行块,因为对象彼此不认识。所以它看起来像这样:

[_stack.childContext performBlock:^
    NSError *error;
    if (![_stack.childContext save:&error]) 
        NSLog(@"Error: %@", error);
    

    [_stack.mainContext performBlock:^
        NSError *error;
        if (![_stack.mainContext save:&error]) 
            NSLog(@"Error: %@", error);
        

        [entity1 setEntity2:entity2];
    ];
];

但是无论我把[entity1 setEntity2:entity2]放在哪里,它都以:

2014-06-22 08:48:24.444 MultiContextualCoreData[1324:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'entity1' between objects in different contexts (source = <Entity2: 0x8c81570> (entity: Entity2; id: 0x8c80000 <x-coredata:///Entity2/tC31696AE-0A0A-424E-9C8E-1E19085F3FB43> ; data: 
    entity1 = nil;
) , destination = <Entity1: 0x8c80200> (entity: Entity1; id: 0x8c80250 <x-coredata:///Entity1/tC31696AE-0A0A-424E-9C8E-1E19085F3FB42> ; data: 
    arg1 = ABC;
    arg2 = DEF;
    entity2 = nil;
))'
*** First throw call stack:
(
    0   CoreFoundation                      0x01b541e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x018d38e5 objc_exception_throw + 44
    2   CoreData                            0x00293b7e _PFManagedObject_coerceValueForKeyWithDescription + 3614
    3   CoreData                            0x002614e9 _sharedIMPL_setvfk_core + 185
    4   CoreData                            0x0027ada7 _svfk_0 + 39
    5   MultiContextualCoreData             0x00002d4a -[AppDelegate test] + 554
    6   MultiContextualCoreData             0x00002acd -[AppDelegate application:didFinishLaunchingWithOptions:] + 605
    7   UIKit                               0x0058d14f -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 309
    8   UIKit                               0x0058daa1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1810
    9   UIKit                               0x00592667 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824
    10  UIKit                               0x005a6f92 -[UIApplication handleEvent:withNewEvent:] + 3517
    11  UIKit                               0x005a7555 -[UIApplication sendEvent:] + 85
    12  UIKit                               0x00594250 _UIApplicationHandleEvent + 683
    13  GraphicsServices                    0x03a07f02 _PurpleEventCallback + 776
    14  GraphicsServices                    0x03a07a0d PurpleEventCallback + 46
    15  CoreFoundation                      0x01acfca5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
    16  CoreFoundation                      0x01acf9db __CFRunLoopDoSource1 + 523
    17  CoreFoundation                      0x01afa68c __CFRunLoopRun + 2156
    18  CoreFoundation                      0x01af99d3 CFRunLoopRunSpecific + 467
    19  CoreFoundation                      0x01af97eb CFRunLoopRunInMode + 123
    20  UIKit                               0x00591d9c -[UIApplication _run] + 840
    21  UIKit                               0x00593f9b UIApplicationMain + 1225
    22  MultiContextualCoreData             0x00002efd main + 141
    23  libdyld.dylib                       0x0219b701 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

我在这里做错了什么?

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

问题是两个对象必须属于同一个上下文才能在它们之间建立关系。在您的情况下,其中一个上下文具有私有类型,它有自己的队列可以工作,主上下文在主队列上工作。这是一种防止您在未来遇到并发问题的方法。

可能的解决方案是

创建entity1,保存主上下文,使用managedObjectID在子上下文中检索它,或者如果更有意义,则使用获取请求,然后只有当你有entity1entity2时才建立关系相同的上下文 或者,简单地说,如果您的逻辑允许,则在同一上下文中创建两个对象。

【讨论】:

谢谢,这对我很有帮助。我使用第一种情况(使用NSManagedObjectID 获取对象,因为我无法在同一上下文中创建这些对象。 我使用属性注入在同一上下文(选项 2)中创建了两个对象,并解决了问题,谢谢 @Naishta 你能举一些例子,你是如何在相同的上下文中创建对象的吗?

以上是关于从子上下文分配对象时非法尝试建立关系的主要内容,如果未能解决你的问题,请参考以下文章

非法尝试在不同上下文中的对象之间建立关系“清单”

NSInvalidArgumentException:非法尝试在不同上下文中的对象之间建立关系

非法尝试在不同上下文中的对象之间建立关系“对象”

单一上下文但“非法尝试在不同上下文中的对象之间建立关系‘xyz’

为啥我的产品->存档因“非法尝试在不同上下文中的对象之间建立关系”压缩类型“而失败?

核心数据:非法尝试建立关系+(空)上下文