NSManagedObjectContext: exception breakpoint stops at save: method, but no log/crash/error
Asked Answered
G

5

52

I'm using CoreData in a multi-threaded iOS-app, and everything seems to work fine - unless I switch on the exception breakpoint in XCode. Whenever I do some CoreData-work, the breakpoint stops at the save:-method on NSManagedObjectContext - but the NSError is nil afterwards. I also have nothing in the log (except: Catchpoint 2 (exception thrown).), the app doesn't crash... So it's pretty hard to tell what's going wrong.

The only clue I have is that I have a single object in updatedObjects: in my NSManagedObjectContext - but there seems nothing wrong with it.

My question is very similar to this question on stackoverflow , but the only answer there doesn't help me; I'm pretty sure that I've got everything covered there.

What could be wrong here? Or are there other possibilities to get some error information?

Thank you very much!

EDIT: showing code is pretty difficult. I'm loading objects with objectID, edit and store them in the context assigned to the current thread. I already checked - the context is always correct for the current thread; each thread has its own context, that shouldn't be the problem. It would be even helpful if only someone could tell me how to get more information from that error/exception - or if I have to care about it after all. It seems to me as if the exception is catched within the `save´-method, so probably its a "normal" behaviour?

Girt answered 1/12, 2011 at 7:1 Comment(3)
@shannoga showing code is impossible, I fear - but see my edit, thanks...Girt
are you using the same managedObjectContext among threads? (context can't be shared among threads)Duplex
@Duplex - no; I'm pretty sure that each thread has it's own managedObjectContext. All I'm sharing is the managedObjectID, not contexts and no objectModels.Girt
P
77

This is normal behavior. CoreData uses exception throwing & handling internally for some of its program flow. I talked to the CoreData people about this. It may seem odd, but that's a design decision they made a long time ago.

When you hit the exception, make sure there's none of your code in the backtrace between your call to -[NSManagedObjectContext save:] and the exception being thrown. Calling -save: is very likely to call back into your code, e.g. if you're observing NSManagedObjectContextObjectsDidChangeNotification, and if you're doing bad things when you're handling those notification, obviously you're at fault.

If you're exiting the -save: method, and the return value is YES, everything is good.

Please note, that you should check the return value, do not use error != nil to check for an error. The correct check is:

NSError *error = nil;
BOOL success = [moc save:&error];
if (!success) {
    // do error handling here.
}
Pessary answered 18/1, 2012 at 15:48 Comment(9)
is there no way to avoid this? it's pretty annoying while debugging, because I'd like to have an exception breakpoint on all the time. This way, it often stops without being a "real" exception...Girt
No, there's no way to avoid this. It's just how CoreData works. You can file a radar and ask Apple to change the code. They're aware of it, but it's probably not very high on the CoreData team's priority list.Pessary
really? I mean - do you have some source for this? That would be disappointing, because - as I mentioned before - it's annoying while debugging :/Girt
Thanks! This has saved me many painful hours of trying to figure out if I was doing something wrong.Lathy
there should be an "inverse" break point checkbox in the breakpoint settingsPredestinarian
I have been running with the -com.apple.CoreData.ConcurrencyDebug 1 with no problems and all of a sudden the code stops at the exact same spot try context.save(). It doesn't seem to be a thread issue; however, how do I make sure that it is in fact NOT a thread issue? The code seems to work fine when the debug switch is off.Pierro
Ranting aside, I have a try catch block around my save() and I still get exceptions that cause app crashes. Could you let me know if using error and the return value could alleviate the problem? The exception stack logged by save are "-[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]" . FYI, I currently don't use the return value of bool and not passing in error param.Schram
is there any way to find out why this happens? Or is it possible that I need to take care of such an "exception"? It's weird that sometimes it happens and sometimes and doesn't, which makes me think as if there's an issue occurring sometimesGirt
You can ignore these spurious breakpoints using the great technique in this answer: https://mcmap.net/q/257598/-ignore-certain-exceptions-when-using-xcode-39-s-all-exceptions-breakpointAllotrope
D
22

You can avoid these useless breaks; as others have pointed out this is normal CoreData behavior (but highly annoying!)

  1. Remove the "All Objective-C Exceptions" breakpoint
  2. Add a Symbolic Breakpoint on objc_exception_throw
  3. Set a Condition on the Breakpoint to (BOOL)(! (BOOL)[[(NSException *)$eax className] hasPrefix:@"_NSCoreData"])
  4. I also like to add an action, debugger command, "po $eax" which usually prints out the exception details

$eax is the correct register for the simulator, $r0 works on devices. You can create two separate breakpoints and enable/disable them as appropriate.

See Ignore certain exceptions when using Xcode's All Exceptions breakpoint for the original answer

Dampen answered 15/3, 2013 at 2:13 Comment(2)
This apparently no longer works. Someone suggested that they had to use "name" in place of "className" but I get the same result. I get a real exception when I enable this. What is the new workaround? I am using the most recent SDK and Xcode.Hammett
Works for iOS 16.4 (BOOL)(! (BOOL)[[$arg2 description] contains:@"_NSCoreData"])Shutt
P
8

I had a similar problem. Eventually, I figured out the problem:

I added an observer to NSManagedObjectContextDidSaveNotification that got freed without removing itself from the notification center. When its memory got assigned to some other object, the notification center tried calling on that object and raised an exception because it couldn't find the right selector. This exception was "invisible" for some reason, but caused CoreData to raise its own exception.

A well placed removeObserver: call fixed the problem.

Hope this may help someone else who encounters this situation.

Pectoralis answered 25/2, 2012 at 16:13 Comment(1)
I had the same issue and it's been bugging me for as long as I can remember, thanks for sharing!Eikon
C
0

I had a similar issue occur in my code. I finally discovered that the issue was due to my model having changed, and the EncryptedCoreData NSPersistentStoreCoordinator I was using wasn't set up for automatic migration, as I had been expecting with MagicalRecord in the past.

The only symptom was this break point, without any other messages. It was solved (temporarily) by deleting and reinstalling the app and permanently by adding model versions and the appropriate key (NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true) to my stack setup.

Cowskin answered 5/5, 2016 at 2:5 Comment(0)
G
0

I struggled with the same problem and what i found is the coordinator will throw an exception when there is a merge problem. I have removed my merge policy (default is the error) and after that the error pointer is no longer nil when you call save. That also gave me confidence that my code is ok.

Graner answered 31/5, 2018 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.