robbiehanson / XMPPFramework

An XMPP Framework in Objective-C for Mac and iOS
Other
5.91k stars 2.09k forks source link

The current thread is not the recognized owner of this NSManagedObjectContext #828

Open am33t opened 7 years ago

am33t commented 7 years ago

I'm getting a concurrency issue with xmpp framework. If I enable this -com.apple.CoreData.ConcurrencyDebug 1

Error - 2016-11-10 15:05:06.494028 SweetCouch-iPhone[610:86198] [error] error: The current thread is not the recognized owner of this NSManagedObjectContext(0x1703c3de0). Illegal access during _retainedObjectWithID:optionalHandler:withInlineStorage:

Multithreading violation exception - CoreData`+[NSManagedObjectContext Multithreading_Violation_AllThatIsLeftToUsIsHonor]:

What I'm doing is when "applicationWillResignActive" gets called, I send a presence packet. As shown in screenshot 3. I'm not sure what's wrong here, plz help.

Thanks.

screen shot 2016-11-10 at 2 56 34 pm screen shot 2016-11-10 at 2 56 45 pm screen shot 2016-11-10 at 3 03 28 pm

jelenadj commented 7 years ago

Same issue here... Another screenshot, crash indicated by xmppStream:didReceivePresence:

screen shot 2016-11-29 at 12 52 34 am
hermannkuschke commented 7 years ago

Same issue. screen shot 2017-01-06 at 12 30 38 pm

sgup77 commented 7 years ago

Did anybody find any solution ??

hermannkuschke commented 7 years ago

Hi, sgup77. What I ended up doing was to store the context in the thread's dictionary and then in the method that returns the managed object context, I return the context from the dictionary if it existed. If it didn't exist, I created a new context and stored it in the dictionary. No more complaints even though I have concurrency debugging turned on. Am I clear enough or would you like to see some code?

sgup77 commented 7 years ago

Hi hermannKuschke, It would be great if you can show me the code.

hermannkuschke commented 7 years ago

Okay, this is in the XMPPCoreDataStorage.m file in the (NSManagedObjectContext)managedObjectContext function.

NSThread *currentThread = [NSThread currentThread]; NSManagedObjectContext *currentManagedObjectContext = (NSManagedObjectContext *)[[currentThread threadDictionary] objectForKey:@"managedObjectContext"];

if (currentManagedObjectContext)
{
    return currentManagedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator)
{
    XMPPLogVerbose(@"%@: Creating managedObjectContext", [self class]);

    if ([NSManagedObjectContext instancesRespondToSelector:@selector(initWithConcurrencyType:)])
        currentManagedObjectContext =
        [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    else
        currentManagedObjectContext = [[NSManagedObjectContext alloc] init];

    currentManagedObjectContext.persistentStoreCoordinator = coordinator;
    currentManagedObjectContext.undoManager = nil;

    [self didCreateManagedObjectContext];
}

[[currentThread threadDictionary] setValue:currentManagedObjectContext forKey:@"managedObjectContext"];
return currentManagedObjectContext;
sgup77 commented 7 years ago

I am getting this error after using the above code. error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'XMPPUserCoreDataStorageObject'

screen shot 2017-01-16 at 5 57 22 pm
hermannkuschke commented 7 years ago

Please past your complete code for the method that we changed.

sgup77 commented 7 years ago

- (NSManagedObjectContext *)managedObjectContext {
    NSThread *currentThread = [NSThread currentThread];
    NSManagedObjectContext *currentManagedObjectContext = (NSManagedObjectContext *)[[currentThread threadDictionary] objectForKey:@"managedObjectContext"];

    if (currentManagedObjectContext)
    {
        return currentManagedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator)
    {
        XMPPLogVerbose(@"%@: Creating managedObjectContext", [self class]);

        if ([NSManagedObjectContext instancesRespondToSelector:@selector(initWithConcurrencyType:)])
            currentManagedObjectContext =
            [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
        else
            currentManagedObjectContext = [[NSManagedObjectContext alloc] init];

        currentManagedObjectContext.persistentStoreCoordinator = coordinator;
        currentManagedObjectContext.undoManager = nil;

        [self didCreateManagedObjectContext];
    }

    [[currentThread threadDictionary] setValue:currentManagedObjectContext forKey:@"managedObjectContext"];
    return currentManagedObjectContext;
}
hermannkuschke commented 7 years ago

Weird error. If you only changed that function, I'm not sure why it's throwing that exception and unfortunately I won't have time to check it out soon. Your function is exactly the same as mine now and the function will ensure that we are using the appropriate managed object context for the current thread. If I have time in the near future, I will try to dig a little.

southfox commented 5 years ago

Hi @hermannkuschke, @sgup77, using the same com.apple.CoreData.ConcurrencyDebug 1 in this pod (tag 4.0.0) I have found that the storageQueue changed, not sure if this is related to this issue yet. First time memory address was:

(lldb) p storageQueue
(OS_dispatch_queue_serial *) $0 = 0x000060000071ff00

Second time different memory address:

(lldb) p storageQueue
(OS_dispatch_queue_serial *) $1 = 0x0000600002252b00

The issue was fixed in my side, because I did something wrong in the initialization of the stream, before my code was:

- (void)setupStream {
    self.xmppStream = [[XMPPStream alloc] init];
    [self.xmppStream setHostName:[self currentHostName]];
    [self.xmppStream setMyJID:myJID];
    self.xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
    self.xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:self.xmppCapabilitiesStorage];
    self.xmppCapabilities.autoFetchMyServerCapabilities = NO;
    self.xmppCapabilities.autoFetchHashedCapabilities = YES;
    self.xmppCapabilities.autoFetchNonHashedCapabilities = NO;
    [self.xmppCapabilities              activate:self.xmppStream];
}

- (void)teardownStream {
    [self.xmppStream disconnect];
    [self.xmppStream removeDelegate:self];
    [self.xmppCapabilities              deactivate];
    self.xmppCapabilities = nil;
    self.xmppCapabilitiesStorage = nil;
    self.xmppStream = nil;
}

But now the code that fixed the issue (always on my side):

- (void)setupStream {
    self.xmppStream = [[XMPPStream alloc] init];
    [self.xmppStream setHostName:[self currentHostName]];
    [self.xmppStream setMyJID:myJID];
    if (!self.xmppCapabilitiesStorage) {
        self.xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
    }
    if (!self.xmppCapabilities) {
        self.xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:self.xmppCapabilitiesStorage];
        self.xmppCapabilities.autoFetchMyServerCapabilities = NO;
        self.xmppCapabilities.autoFetchHashedCapabilities = YES;
        self.xmppCapabilities.autoFetchNonHashedCapabilities = NO;
    }
    [self.xmppCapabilities              activate:self.xmppStream];
}

- (void)teardownStream {
    [self.xmppStream disconnect];
    [self.xmppStream removeDelegate:self];
    [self.xmppCapabilities              deactivate];
    self.xmppStream = nil;
}

I've found that with my change com.apple.CoreData.ConcurrencyDebug 1 does not complain anymore on the pod.

Hope this helps.

erhnby commented 3 years ago

Hi everyone. Is there any update regarding this issue?