CoreData:在块中发布的对象“错误:在从其上下文中删除托管对象后对其进行变更”

时间:2017-07-31 05:23:27

标签: ios objective-c core-data nsautoreleasepool

此代码依赖于Robbie Hanson XMPPFramework 的旧分叉版本的CoreData设置。

我正在改造一个由托管对象CoreData支持的数据结构,基本上保留对所讨论的数据结构中的NSManagedObjectID的引用,然后让访问者通过支持来获取/设置数据结构属性核心数据中的数据。

我间歇性地收到以下错误(类似于):

CoreData: error: Mutating a managed object 0xd00000000014000a <x-coredata://90C02501-4756-44F0-ABA6-B725192772A6/ZZXMPPOneToOneInboxItemCoreDataObject/p5> (0x1742971b0) after it has been removed from its context.

我在设置和获取时都收到错误。显然,“获取”错误不是“改变托管对象”错误,但堆栈跟踪与发布作为罪魁祸首相同。

以下是一个示例setter:

- (void)setMamUUID:(NSString *)mamUUID
{
    ZZXMPPInboxCoreDataStorage *storage = [ZZXMPPInboxCoreDataStorage sharedInstance];
    [storage executeBlock:^{
        ZZXMPPOneToOneInboxItemCoreDataObject *backingObject = (ZZXMPPOneToOneInboxItemCoreDataObject *)[storage inboxItemInsideBlockWithObjectID:self.itemCoreDataObjectID];

        backingObject.mamUUID = mamUUID;
    }];
}

和一个吸气者:

- (NSString *)mamUUID
{
    ZZXMPPInboxCoreDataStorage *storage = [ZZXMPPInboxCoreDataStorage sharedInstance];
    __block NSString *_mamUUID;

    [storage executeBlock:^{
        ZZXMPPOneToOneInboxItemCoreDataObject *backingObject = (ZZXMPPOneToOneInboxItemCoreDataObject *)[storage inboxItemInsideBlockWithObjectID:self.itemCoreDataObjectID];

        _mamUUID = [backingObject mamUUID];
    }];

    return _mamUUID;
}

inboxItemInsideBlockWithObjectID:是一个帮助程序,意味着在executeBlock:内运行,看起来像这样

- (ZZXMPPInboxBaseMemberCoreDataObject *)inboxItemInsideBlockWithObjectID:(NSManagedObjectID *)objectID
{
    ZZXMPPInboxBaseMemberCoreDataObject *inboxItem = nil;
    inboxItem = [[self managedObjectContext] objectWithID:objectID];
    if (nil == inboxItem) {
        NSLog(@"..Unable to retrieve an Inbox Item with objectID %@.", objectID);
    }

    return inboxItem;
}

两者中引用的“storage”对象是XMPPFramework中的XMPPCoreDataStorage对象,而executeBlock:将此作为主要代码:

dispatch_sync(storageQueue, ^{ @autoreleasepool {

block();

// Since this is a synchronous request, we want to return as quickly as possible.
// So we delay the maybeSave operation til later.

dispatch_async(storageQueue, ^{ @autoreleasepool {

    [self maybeSave:OSAtomicDecrement32(&pendingRequests)];
}});

}});

错误是objc_object::release()(后续跟踪),并在上面“setter”代码中的块末尾的调试器中显示。

以下是完整的回溯:

(lldb) bt
* thread #1, queue = 'ZZXMPPRoomHybrid', stop reason = EXC_BAD_ACCESS (code=1, address=0x3a8e9bec8)
    frame #0: 0x0000000180459704 libobjc.A.dylib`objc_object::release() + 8
  * frame #1: 0x000000010009c1f4 MyApp`__29-[ZZConversation setMamUUID:]_block_invoke((null)=0x000000016fda6838) at ZZConversation.m:280
    frame #2: 0x00000001003da11c MyApp`__36-[XMPPCoreDataStorage executeBlock:]_block_invoke((null)=0x000000016fda67b0) at XMPPCoreDataStorage.m:1063
    frame #3: 0x0000000103c55218 libdispatch.dylib`_dispatch_client_callout + 16
    frame #4: 0x0000000103c61dc8 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 156
    frame #5: 0x0000000103c65adc libdispatch.dylib`_dispatch_barrier_sync_f_slow + 452
    frame #6: 0x00000001003da098 MyApp`-[XMPPCoreDataStorage executeBlock:](self=0x00000001702e5100, _cmd="executeBlock:", block=0x000000010009c148) at XMPPCoreDataStorage.m:1061
    frame #7: 0x000000010009c0d8 MyApp`-[ZZConversation setMamUUID:](self=0x0000000174223d60, _cmd="setMamUUID:", mamUUID=@"50a35939-f48c-4011-8cfe-b5edf3641e20") at ZZConversation.m:276
    frame #8: 0x00000001000a3c80 MyApp`-[ZZConversation mamRequestWasSentWithUUID:](self=0x0000000174223d60, _cmd="mamRequestWasSentWithUUID:", uuid=@"50a35939-f48c-4011-8cfe-b5edf3641e20") at ZZConversation.m:886
    frame #9: 0x00000001000af894 MyApp`__58-[ZZXMPPMAMCoreDataStorage requestMessageArchiveWithUser:]_block_invoke((null)=0x00000001742567a0) at ZZXMPPMAMCoreDataStorage.m:73
    frame #10: 0x0000000103c55218 libdispatch.dylib`_dispatch_client_callout + 16
    frame #11: 0x0000000103c61334 libdispatch.dylib`_dispatch_continuation_pop + 708
    frame #12: 0x0000000103c6ff94 libdispatch.dylib`_dispatch_source_latch_and_call + 204
    frame #13: 0x0000000103c57300 libdispatch.dylib`_dispatch_source_invoke + 836
    frame #14: 0x0000000103c5a05c libdispatch.dylib`_dispatch_main_queue_callback_4CF + 652
    frame #15: 0x00000001819b6810 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    frame #16: 0x00000001819b43fc CoreFoundation`__CFRunLoopRun + 1660
    frame #17: 0x00000001818e22b8 CoreFoundation`CFRunLoopRunSpecific + 444
    frame #18: 0x0000000183396198 GraphicsServices`GSEventRunModal + 180
    frame #19: 0x00000001879297fc UIKit`-[UIApplication _run] + 684
    frame #20: 0x0000000187924534 UIKit`UIApplicationMain + 208
    frame #21: 0x000000010006a688 MyApp`main(argc=5, argv=0x000000016fda7a60) at main.m:16
    frame #22: 0x00000001808c55b8 libdyld.dylib`start + 4
(lldb) 

我不确定为什么托管对象会在块中释放。 @autoreleasepool围绕块,在“sync”块运行时不应释放任何内容。

间歇性地发生这种情况,我可以多次运行应用程序,然后再次浮出水面。通常,它出现在“ getter ”而不是“ setter ”,但由于它发生在两者上并且两者的代码相似,我认为不重要

为什么此时会释放此托管对象实例?

0 个答案:

没有答案