Core Data swallowing uncaught exception - ios

I have run into a disturbing/baffling bug. Core Data seemed to be swallowing its own exception! When using the (super-useful) CoreDataHelper, I had written a badly formed fetch that resulted in a "Unimplemented SQL generation for predicate" exception. That part's simple, what's really weird is that this exception was being caught somewhere and swallowed, meaning that my code just skipped the rest of the method after that fetch and returned to the main loop without any console messages. Quite infuriating.
Eventually I was able to wrap the actual fetch request in a #try statement and #catch the exception:
#try{
fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"fetch successful");
}
#catch (NSException* exception) {
NSLog(#"caught exception!\n\n%#\n\n%#\n\n%#",[exception name], [exception reason], [exception userInfo]);
}
This let me figure out what it was, but it still makes no sense that it would be getting caught somewhere. I have not used #try/#catch anywhere else in my code other than to test this.
I also tried creating a blank Core Data project and using CoreDataHelper without the #try/#catch statement to try and isolate the problem, with nothing else in the project, CoreDataHelper works as it should, returning:
CoreDataTest[1044:11603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unimplemented SQL generation for predicate ("test" LIKE attribute)'
So something in my project is catching and ignoring this exception, but it's not me unless I can somehow do that without using #catch.
What could it be?!

Got it!
I'm using an external accessory (Linea Pro-4 barcode scanner/MSR) that has its own library, and that is what is catching the exception, even in their newest version of the framework.
I set up my blank test project to connect to the accessory before running the same fetch request, and bam! Swallows the exception!

Related

iOS 64bit #try {... } #catch {...} not working

I have a very peculiar issue.
Recently I added 64bit support to my iOS project (arm64), ever since doing that I started receiving uncaught exceptions for segments of my code inside #try...#catch (I'm using Crashlytics for crash reporting). I managed to reproduce the problem with the following lines of code anywhere in my app (I wrote them inside init of one of my view controllers):
#try {
NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
NSString *s;
m[s] = #"poop";
} #catch (NSException *e) {
NSLog(#"POOP");
}
The exception gets caught by the UncaughtExceptionHandler instead of the #catch clause. I'm confused as to what can cause this. The output in the console:
2015-02-22 19:19:53.525 [391:30650] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: key cannot be nil'
*** First throw call stack:
(0x18823a59c 0x1989400e4 0x1881251f8 0x10011e2f4 0x10011e068 0x10010e480 0x10010db78 0x10010d944 0x1000a8050 0x100075d88 0x100075160 0x100142044 0x100141f6c 0x18c9ecaa0 0x18caa1fb4 0x18caa1eb0 0x18caa134c 0x18caa0ff8 0x18caa0d18 0x18caa0c98 0x18c9e9648 0x18c341994 0x18c33c564 0x18c33c408 0x18c33bc08 0x18c33b98c 0x18cc76dbc 0x18cc77c68 0x18cc75dec 0x1904b162c 0x1881f2a28 0x1881f1b30 0x1881efd30 0x18811d0a4 0x18ca573c8 0x18ca523c0 0x1000747d8 0x198faea08)
libc++abi.dylib: terminating with uncaught exception of type NSException
I tried removing the custom exception handler that I have and disabling Crashlytics, still no success.
As soon as I remove arm64 from ARCHS and VALID_ARCHS the code works and the exception is caught as expected.
Any information will be appreciated!
Small update - our XCTests also started not to catch exceptions, up until now the behaviour only happened on physical 64bit phones.
After a long session of git-bisecting the culprit was the following linker flag
-no_compact_unwind
I Used BlocksKit v2.2.0 which still had that flag even though it stopped using libffi (latest version of BlocksKit removed that unneeded flag). As soon as I removed that linker flag 64bit #try...#catch blocks started to work again.
I still don't have complete understanding of why this behaviour happens but I'm going to dig a bit more and update this thread if I find anything interesting.
phew
On iOS and Objective-C Exceptions are only to be used for un-recoverable programming errors, not for program execution control.
In particular they do not handle catches accross stack frames inthe APIs.

Is the save: method thread-safe?

In short
Can I call
[moc performBlockAndWait:^{
[moc save:NULL] ;
}];
from different threads at the same time?
In long
I add a crash similar to this one, namely:
Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
2011-06-15 11:36:59.864 myApp[457:607] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
*** Call stack at first throw:
The program crashes on this command:
[moc performBlockAndWait:^{
[moc save:NULL] ;
}];
As I launch the same process (with difference parameters) to as many threads as possible (with the help of NSOperationQueue), this command might be called by different threads as the same time.
Could that be a problem? Or the method performBlockAndWait: already deals with that?
I ask you the question to know if I need to create a singleton that would manage the saving to the moc.
-save: must be called from the thread/queue that created the context.
calling -performBlockAndWait: does avoid calling it from the wrong thread.
You must pass in a NSError to the -save: method and you need to watch the result of the -save: to determine if an error is occurred. That is your singular way of knowing if an error occurred. Passing in NULL is asking for trouble.
The error you are currently seeing is not caused from the save directly. It is most likely caused because you are listening to NSManagedObjectContextDidSaveNotification somewhere else and doing something incorrect there. Search your code for that constant and review the code associated with it.

Do not stop test execution on XCTAssertThrowsSpecific

Using XCTest, a test does the following:
XCTAssertThrowsSpecificNamed([does something that breaks], NSException, NSInvalidArgumentException);
I don't want the debugger to stop on the NSException that I know will occur but I want it to still stop on other exceptions that might occur.
Basically we don't have a choice. I still consider it an xCode bug because you already told xCode an exception will be thrown, and what exception it will be. Why provide XCTAssertThrows if it's an exception you're not "expecting"?
Obviously it's for exceptions you are expecting, which #nhgrif argues should be an error, not an exception. Might be a good point, but i do want my program to crash if this case ever happens, because I can't handle it.
So the real question is more why not disable the debugger on that exception only? Probably because they haven't gotten around to it. I'd suggest opening a bug/feature request with Apple. I'd love for someone to contradict me on this (please comment!) but until then, I'll live with this issue (disable debugger when running all my tests).
--> https://stackoverflow.com/a/22393643/1701430
"Why does the test stop when the execution is thrown?"
Because you have a breakpoint, which stops execution.
"Why, after removing the breakpoint, does my application crash when the exception is thrown?"
Because you have an unhandled exception. Unhandled exceptions cause your program to crash.
"How can I handle an exception so it won't crash my program?"
The easy answer to this question is to simply NOT throw an exception. In other programming languages, like Java, this is perfectly standard. But in Objective-C, we don't really do exceptions. In Objective-C, exceptions should be saved for TRULY exceptional behavior.
With that said, and a strong suggestion for you to find another way to handle whatever it is you're trying to handle, this is how you handle an exception in Objective-C:
#try {
// code that could throw an exception
}
#catch (NSException *e) {
// handle the exception...
}
#finally {
// post try-catch code, executed every time
}

How to catch a database exception in ios?

I have searched a lot on the internet on catching an sqlite exception.But all I could come across was this general exception
#catch (NSException *exception) {
}
What type of exception can I use for sqlite exception handling?
Generally, SQLite does not return exceptions for recoverable errors. Rather, it returns an error code which you must check after each operation.
Some "wrapper" APIs for SQLite may return exceptions, but that would be a function of the particular API.

ios error on label

how to soive this to stop warning message for this? am trying to put error on label. Does try catch really prevent crashing app?
#catch (NSException *ex) {
errorLbl.text =ex;
}
Instead of trying to catch a crash, you should make sure that code will not crash altogether. However, you can always convert the NSException to NSString
#catch (NSException *ex) {
errorLbl.text = [NSString stringWithFormat:#"%#",[ex reason]];
}
NSException
#interface NSException : NSObject <NSCopying, NSCoding> {
#private
NSString *name;
NSString *reason;
NSDictionary *userInfo;
id reserved;
}
This question is hard to understand, but if your asking, will that Catch catch every exception that is based off of a NSException, then the answer is yes, with a small issue.
You can catch it, but since your not doing anything about it, the code will continue after the catch. If your app is crashing, then what will happen is you will fill some label with the error, but it wont mean the app is in a stable position, it might just keep crashing.
NSException's reason contains a "human readable" reason that you could display, like:
#catch (NSException *ex) {
errorLbl.text = ex.reason;
}
See the NSException reference for more info.
It's worth noting that exceptions in Objective-C (unlike in other languages) are intended to be used for programming or unexpected runtime errors, not normal program flow. The docs state:
Important: You should reserve the use of exceptions for programming or
unexpected runtime errors such as out-of-bounds collection access,
attempts to mutate immutable objects, sending an invalid message, and
losing the connection to the window server. You usually take care of
these sorts of errors with exceptions when an application is being
created rather than at runtime.
...
Instead of exceptions, error
objects (NSError) and the Cocoa error-delivery mechanism are the
recommended way to communicate expected errors in Cocoa applications.
For further information, see Error Handling Programming Guide.
See the Error Handling Programming Guide.

Resources