I am working on some API (Crittercism) to report handled exceptions in the client to server.
The client API takesNSException as the input parameter. I have to add some application context info string(NSString) also to theNSException before calling the API.
How I can do it using Objective-C.
NSString* appContextString;
NSString *test = #"test";
unichar a;
int index = 5;
#try {
a = [test characterAtIndex:index];
}
#catch (NSException *exception) {
// add app context to exception before reporting to Crittercism.
[Crittercism logHandledException:exception];
}
I have to append appContextString to exception.
You could build a new NSException object from attributes of the old one, but that seems very messy. As you are just logging the handled exception, I would simply log the "app context" before that:
#try {
a = [test characterAtIndex:index];
}
#catch (NSException *exception) {
NSString *appContext = #"...";
[Crittercism leaveBreadcrumb:appContext];
[Crittercism logHandledException:exception];
}
You have to copy it. This can be done easily. An instance of NSExeption has three important properties:
name
reason
user info
When copying it, you can add a string to the user info dictionary:
NSMutableDictionary *userInfo = [exception.userInfo mutableCopy];
userInfo[#"YourPrivateKey"] = contextString;
NSException *extendedException = [NSException exceptionWithName:exception.name reason:exception.reason userInfo:userInfo];
I think as a caveat that you will lose the call stack. You can read that and put it in the user info dictionary, too. I do it a similar way on Objective-Cloud.
userInfo[#"CallStackSymbols2] = exception.callStackSymbols;
Analogous with call stack return addresses.
I do not think that this is very nice, because the call stack becomes a part of the exceptions's user info instead of the exception itself. For me this is no caveat, because I sent the exception as JSON, therefore the call stack as JSON object. I cannot say, whether this is a problem for you.
Related
I wanna check the UITextField is String or number by using try catch.
But it seems doesn't work. Here is my code:
- (IBAction)add {
#try {
double firstNumber = self.firstNumber.text.doubleValue;
double secondNumber = self.secondNumber.text.doubleValue;
Calculator *calcu = [[Calculator alloc] initWithFirstNumber:firstNumber andSecondNumber:secondNumber andOperation:#"+"];
self.result.text = calcu.calculateTwoNumber;
}
#catch (NSException *exception) {
self.result.text = #"Please enter right number!";
}
#finally {
}
}
Follow code:
#try {
self.labelName.text=[arrName ObjectAtIndex:indexPath.row];
}
#catch (NSException *exception) {
NSLog(#"Something missing...");
}
#finally {
}
What Claus Bönnhoff wrote in the comments cannot be overemphasized: Objective-C is not Java or C#.
The accepted way to use exceptions in Obj-C is for unrecoverable errors, not simple flow control.
The answer to your question, then, is that exceptions should be used very rarely. In several years of iOS development, I haven't used them a single time. I also have not come accross them in anyone else's code.
I have, however, encountered exceptions thrown by the Obj-C runtime, which I suppose gives some indication of what their role might be.
I have 10 Classes in my project,At present i was placing try catch block in each and every method in all 10 classes to catch the exception which seems to be a bulky code.
Now i want to maintain a Single try catch block through out the project, means if any exception occurred in all my 10 classes that should be catched by try catch block.
Is it possible to do like this…
NSArray *arr=[[d1 objectForKey:#"Time"] componentsSeparatedByString:#" "];
NSArray *arr1=[[arr objectAtIndex:1] componentsSeparatedByString:#":"];
Here my object “Time” is coming from the Service.
so if the object is empty it may cause to
Array out of index Exception.
I know which i can solve by comparing the length of String.So, if suppose if forgot to compare length in some cases.
In that case i want to catch the exception and i want to post it to my server.
#catch (NSException *exception) {
NSString *stacktrace=[exception.reason stringByReplacingOccurrencesOfString:#"<" withString:#""];
stacktrace=[stacktrace stringByReplacingOccurrencesOfString:#">" withString:#""];
// NSString *strClass = NSStringFromClass([self class]);
NSString *strClass = [NSString stringWithFormat:#"%# : %#",NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
Item* myStore = [Item sharedStore];
myStore.strErrorDescription=exception.name;
myStore.strErrorStack=stacktrace;
myStore.strErrorPageName=strClass;
[myStore PostError];// To Post the exception to My server.
ErrorView *errorView=[[ErrorView alloc]initWithNibName:#"ErrorView" bundle:nil]; [self presentViewController: errorView animated:NO completion:nil];
}
Thank you.
The real answer here is You're Doing It Wrong.
Exceptions in Objective-C are different from those in other languages like Java or Ruby. In particular, they tend to be "non-recoverable", meaning that once some code throws an exception, a number of assumptions about the state of memory allocations, etc become false, and your program is probably on its way to crashing.
The overall approach Apple recommends is to treat exceptions as a symptom of a programmer error. The example you give is the same one they do: neglecting to check the length of an NSArray. You should aim to find and eliminate those during your development process; the best way to do that is probably to let your program crash as a result of the exception, then find and fix the offending code.
I am getting an exception from my published application which is:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x19a8a170'
and happens because of:
#property(nonatomic,retain)NSMutableDictionary *settings;
settingsData = [NSKeyedArchiver archivedDataWithRootObject:self.settings];
As this is a remote report, I cannot debug or find out the problematic object that was added to NSMutableDictionary without conforming to NSCoding protocol. Because of this reason, I am trying to find that object when an exception occurs. Remove it from the array and log it to learn what it is.
So, I use the following block:
NSData* settingsData = nil;
#try {
settingsData = [NSKeyedArchiver archivedDataWithRootObject:self.settings];
}
#catch (NSException *exception) {
for (id key in self.settings) {
id value = [self.settings objectForKey:key];
if(![value respondsToSelector:#selector(encodeWithCoder:)]){}
}
}
#finally {
}
However, this exception is never catched on device and simulator. (tested on iOS7 and iOS8).
I don't want to test parameters if there are no exceptions every single time...
I don't want to test values while setting them to dictionary. (As already added ones will also create problem too)
Is there a way to catch this kind of exception?
I have a code for fetching json. It works perfectly fine, when my device is connected to internet, but it crashes if there is no internet connection.
I have surrounded that particular line of code with try / catch block, but it doesn't seem to do the trick.
Of course, I can do a workaround, and first check if there is internet connection and then call the method I need, but I want to understand this.
Why #catch isn't triggered in this case, and what to do to handle this exception in this case?
Here is the code:
#try {
NSError *error;
NSMutableDictionary* json = [NSJSONSerialization
JSONObjectWithData:_jsonData
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
...
#catch (NSException *exception) {
[_indicator stopAnimating];
_indicator.hidden = YES;
[self popUp];
}
So, the exception occurs when trying to populate json dictionary.
Your JSON data _jsonData seems to be obtained before try~catch block, and then the source of the issue should be out of the block. Then you need to find out where the data is obtained from the internet, and install the try~catch block at there.
I know in Android, there is a pretty reliable built-in system for notifying me of crashes that happen. They almost immediately write the stack trace and some other info into a Google doc. it works tremendously well.
I started researching the same thing for ios, and I am not finding anything similar that is equally effective. I read this article: Xcode storyboard: Why does the iPad storyboard show iPhone sized views?
but I am not sure if this is still the case. Could anyone recommend me what to use for crash reports that happen on user devices?
Thanks!
I'm using Flurry with an uncaughtExceptionHandler and GTMStackTrace
The exception handler can look like this:
void uncaughtExceptionHandler(NSException *exception)
{
#try
{
NSString *fullBacktrace = GTMSBStackTraceFromException(exception);
NSMutableString *backtrace = [NSMutableString stringWithUTF8String:""];
NSArray *backtraceArray = [fullBacktrace componentsSeparatedByString:#"\n"];
for (id entry in backtraceArray)
{
NSRange testRange = [entry rangeOfString:[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleName"]];
if (testRange.length)
{
[backtrace appendString:entry];
}
}
NSCharacterSet *whitespaces = [NSCharacterSet whitespaceCharacterSet];
NSPredicate *noEmptyStrings = [NSPredicate predicateWithFormat:#"SELF != ''"];
NSArray *parts = [backtrace componentsSeparatedByCharactersInSet:whitespaces];
NSArray *filteredArray = [parts filteredArrayUsingPredicate:noEmptyStrings];
NSString *strippedBacktrace = [filteredArray componentsJoinedByString:#" "];
[FlurryAnalytics logError:#"uncaughtExceptionHandler"
message:[NSString stringWithFormat:#"%#", strippedBacktrace ? strippedBacktrace : #"no matching backtrace"]
exception:exception];
}
#catch (NSException *exception)
{
NSLog(#"whoa! could not handle uncaught exception!");
[FlurryAnalytics logError:#"uncaughtExceptionHandler"
message:#"no matching backtrace"
exception:exception];
}
}
Testflight has a good crash log too.
What you can do is create a new uncaught exception handler, then register it via NSSetUncaughtExceptionHandler. That way, each crash can be intercepted just before the kill, and you can log it / save it somewhere to upload.
(I've personally used the method described in this link : http://cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html)
Setting an uncaughtexception handler will only give you a subset of crash reports, and also the details of the reports you get that way are very limited. You don't get stack traces of all threads, you don't get the stacktrace of the exception where the crash really happened, and you don't get the line numbers of your code where the crash happened. In addition you don't get any crash reports caused by signal handlers.
In addition you should NOT run any objective-C code once a crash occurs since it is not async-safe. See this article for more information about it: Reliable Crash Reporting
If posted some more details on what you can do as answers to the following questions: Crash analytics and reporting for iOS and iOS crash log catch, debug info.. Catch and send via email to the Dev team