2

I am experiencing a problem with CoreData when an NSOperation that download stuff in the background is beeing deallocated.

I am using the nested managed object contexts and the context the operation uses has everything guarded in -[NSManagedObjectContext performBlock:]

However, around the time the operation is beeing deallocated, I get a crash with the following stack:

#0  0x022d9098 in objc_msgSend ()
#1  0x00bfb903 in _PFObjectIDFastHash64 ()
#2  0x029fbdb0 in __CFDictionaryHashKey ()
#3  0x029e13e2 in CFBasicHashFindBucket ()
#4  0x029e0e2d in CFDictionaryGetValue ()
#5  0x00c0a408 in -[NSPersistentStoreCache incrementRefCountForObjectID:] ()
#6  0x00c0a37e in -[NSSQLCore managedObjectContextDidRegisterObjectsWithIDs:] ()
#7  0x00cd378c in -[NSPersistentStoreCoordinator(_NSInternalMethods) _informAffectedStoresOfInterestByChildContextInObjectsWithObjectIDs:withSelector:] ()
#8  0x00c0a29f in -[NSPersistentStoreCoordinator(_NSInternalMethods) managedObjectContextDidRegisterObjectsWithIDs:] ()
#9  0x00cb41db in __95-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:]_block_invoke_0 ()
#10 0x00c39cc1 in internalBlockToNSManagedObjectContextPerform ()
#11 0x025af014 in _dispatch_client_callout ()
#12 0x0259ed5f in _dispatch_barrier_sync_f_invoke ()
#13 0x0259eaa3 in dispatch_barrier_sync_f ()
#14 0x00c39c8b in _perform ()
#15 0x00c3a6e9 in -[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:] ()
#16 0x00cb41db in __95-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:]_block_invoke_0 ()
#17 0x00c39cc1 in internalBlockToNSManagedObjectContextPerform ()
#18 0x025a0731 in _dispatch_barrier_sync_f_slow_invoke ()
#19 0x025af014 in _dispatch_client_callout ()
#20 0x0259f7d5 in _dispatch_main_queue_callback_4CF ()
#21 0x02a12af5 in __CFRunLoopRun ()
#22 0x02a11f44 in CFRunLoopRunSpecific ()
#23 0x02a11e1b in CFRunLoopRunInMode ()
#24 0x02dff7e3 in GSEventRunModal ()
#25 0x02dff668 in GSEventRun ()
#26 0x0120bffc in UIApplicationMain ()
#27 0x0000285d in main at /Users/mochs/Projects/12_IP_Lufthansa_Next/Lufthansa/Supporting Files/main.m:16
#28 0x00002785 in start ()

I really have no clue what's going on. What I know is:

  • I am using ARC
  • I am using nested managed object contexts
  • The operation schedules and executes stuff in a shared NSThread with its own runloop
  • The thread is shared and is not released when the operation is being deallocated
  • Shortly after -[NSOperation dealloc] the app crashes in the main thread
  • I fixed the same issue a couple of ours before with a [context reset] in the NSOperation's dealloc method. At this time the concurrency type was NSConfinementConcurrencyType and I didn't use performBlock:
    • Because of some changes I needed to change the concurrency type of the context to NSPrivateQueueConcurrencyType and make it use performBlock:, now the error is back.

I am pretty sure that the call to reset wasn't really solving the problem but instead just fixing the crash. I have no clue what really leads to such a crash.

Does anybody know what this error is about?

Best regards, Michael

Michael Ochs
  • 2,846
  • 3
  • 27
  • 33
  • *"Shortly after -[NSOperation dealloc] the app crashes..."*. What does that mean? Are you calling dealloc? If not, how do you know? – Tom Harrington Jul 26 '13 at 16:51
  • I set a breakpoint there. After this there seems to be something going on with the main thread context and it crashes. – Michael Ochs Jul 26 '13 at 17:20
  • 1
    Hard to say for sure. The backtrace looks like there was a `performBock:` that had not executed, and the crash occurred in that block. Calling `reset` presumably cancelled the `performBlock:`. Maybe you have a `performBlock:` somewhere that relies on the operation queue still existing, and crashes if it doesn't? – Tom Harrington Jul 26 '13 at 17:50
  • If you set a breakpoint in `dealloc`, you are obviously overriding the method. Maybe you forgot to call `[super dealloc];`. – Mundi Jul 26 '13 at 20:25
  • I added a `performBlockAndWait:` in the dealloc to make sure there is nothing left that hasn't executed. Same issue. So the queue seems to be empty before deallocation and this is not the problem. @Mundi: I use ARC, so no `[super dealloc]` necessary! – Michael Ochs Jul 29 '13 at 08:03
  • are you anywhere in your code fetching objects by ID? i found out that existingObjectWithID is the best way to do that. – João Nunes Nov 11 '13 at 15:37

2 Answers2

0

As far as I know Core Data isn't thread safe. On github you can find these extension that would make Core Data thread safe Adam Roth

Andrea
  • 26,120
  • 10
  • 85
  • 131
  • As I stated above: I use the `performBlock:` methods and the `-initWithConcurrencyType:` method to initialize the context! – Michael Ochs Jul 29 '13 at 08:30
  • Ops, sorry.. I had a similar problem in a download manager, the problem was caused by incorrect sequence of setting finished and cancelled property in NSOperation subclass in an NSOperationQueue. I also opened a question http://stackoverflow.com/questions/9409994/cancelling-nsoperation-from-nsoperationqueue-cause-crash – Andrea Jul 29 '13 at 08:38
0

Finally I found the issue. When saving all contexts up to the persistent store, is used a method saveToPersistentStore: that I used from RestKit, with some minor changes to match our requirements.

The following line, that should work as a fix on iOS5, caused the issue, at least on iOS6:

[contextToSave obtainPermanentIDsForObjects:[[contextToSave insertedObjects] allObjects] error:&localError];

I have to further investigate wether the issue only occurs on iOS6 (right know, we are not targeting something else) before I send them an issue request, but simply removing this line fixed the issue.

Michael Ochs
  • 2,846
  • 3
  • 27
  • 33
  • @Mundi which error? You mean the fix in `RestKit`? This is the original implementation with an explanation of the bug: https://github.com/RestKit/RestKit/blob/d97c07acc2142e5912da9e79e9086bb2686d4ac8/Code/CoreData/NSManagedObjectContext%2BRKAdditions.m#L39 – Michael Ochs Jul 29 '13 at 14:00
  • The `localError` variable above. – Mundi Jul 29 '13 at 14:38
  • It is nil. The call just seems to bring the context in an invalid state. It doesn't even crash there. It crashes a couple of run loop cycles later. – Michael Ochs Jul 29 '13 at 16:42
  • funny for me adding this line solved my crash :) This line of code must be coordinated when you create an object in a context and then access it in another context. – João Nunes Sep 17 '13 at 14:06
  • What is the purpose of calling this line in the first place? I'm having a similar issue with AlecrimCoreData's contexts. – AnthonyMDev Sep 29 '16 at 20:04