How to use try catch in iOS? - ios

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.

Related

Objective-C : appending a NSString to NSException reason

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.

#try fails to catch EXC_I386_GPFLT?

I have a simple wrapper for NSLogv. It works fine, except throws an exception if there are too many placeholders in the format string. I would like to catch that exception, but this #try block doesn't work. Why?
- (void)error:(NSString *)formatString, ...;
{
#try {
va_list arglist;
va_start(arglist, formatString);
formatString = [NSString stringWithFormat:#"ERROR: %#", formatString];
NSLogv(formatString, arglist);
va_end(arglist);
}
#catch (NSException *exception) {
// Handle exception ...
}
}
Here is an example that throws an exception:
[[MYLogger error:#"%# %#", value];
#try catches exceptions. You are trying to catch a signal.
My advice: Don't even try.

IOS download data with JSON for a IPhone APP

i try to download data from a webserver with json into my ios app.
That´s the json output
{
"responseHeader":{
"status":0,
"QTime":37,
"params":{
"wt":"json",
"q":"title:ios"
}
},
"response":{
"numFound":348,
"start":0,
"docs":[
{
"edition":"2. ed.",
"illustrated":"Not Illustrated",
"id":"BSZ117259543",
"author":"Raw, Charles",
"title":"IOS /",
"spelling":"Raw, Charles (DE-576)180904566 Do you sincerely want to be rich? span. IOS / Charles Raw; Bruce Page; Godfrey Hodgson 2. ed. São Paulo : Ed. Expressão e Cultura, 1972 XV, 496 S. Page, Bruce (DE-576)162468539 aut Hodgson, Godfrey (DE-576)161444822 aut",
"last_indexed":"2012-09-02T01:11:38Z",
"recordtype":"marc",
"title_auth":"IOS /",
"title_sort":"ios",
"title_short":"IOS /",
"fullrecord":"00985nam a22003372"
}
]
}
}
The Code of my project:
- (void)viewDidLoad
{
[super viewDidLoad];
// 1 Schritt
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//code executed in the background
// 2
//NSData* kivaData = [NSData dataWithContentsOfURL:[NSURLURLWithString:#"http://api.kivaws.org/v1/loans/search.json?status=fundraising"]];
NSData* kivaData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://bib.flux-services.net/solr/biblio/select?q=title:ios&wt=json"]];
//3
NSDictionary* json = nil;
if (kivaData) {
json = [NSJSONSerialization JSONObjectWithData:kivaData options:kNilOptions error:nil];
}
//4
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUIWithDictionary:json];
});
});
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)updateUIWithDictionary:(NSDictionary*)json {
#try {
label.text = [NSString stringWithFormat:#"%# from %#",
json[#"docs"][0][#"title"],
json[#"docs"][0][#"edition"],
//json[#"loans"][0][#"loan_amount"],
//json[#"loans"][0][#"use"],
nil
];
}
#catch (NSException *exception) {
[[[UIAlertView alloc]initWithTitle:#"Error"
message:#"Could not parse the json feed."
delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil]show];
NSLog(#"Exception: %#", exception);
}
When I run the programm then the IPhone simulator could not display the data.
I haven´t any idea where´s the problem!?!
Have anybody a idea or a solution???
First, exceptions are for programming errors. You don't catch exceptions. If you get exceptions, your program crashes, you find the reason, you fix the code. That's how it's done in Objective-C. People might thing you are a Java programmer.
Second, an NSLog of the dictionary you received would be useful. What you printed doesn't match your code.
Third, when you get JSON data, you just check everything. You check that you've received a dictionary. You check that there is a property named "docs" and that it is an array. You check that it has at least one element. You get the first element and check that it is a dictionary. You check that the dictionary has a property "title" and a property "edition" and that they are strings and so on.
Fourth, to help keeping your sanity, define an object representing what's in the JSON data, taking a dictionary as an initialiser, and extract everything into that object. So from then on you are in safe NSObject territory.
Fifth, what on earth do you think happens when your users read "Could not parse the JSON feed"? Their poor brains will explode. Error messages are for users, not for programmers.

Objective C - Catch exception raised from inside a block

I'm using the following code in app:
#try {
if(!self.usernameField.text || [self.usernameField.text isEqualToString:#""])
[NSException raise:#"Invalid value for username" format:#"Please enter your username."];
if(!self.passwordField.text || [self.passwordField.text isEqualToString:#""])
[NSException raise:#"Invalid value for password" format:#"Please enter your password."];
[LoginManager
userLogin:self.usernameField.text
andPassword:self.passwordField.text
success:^(AFHTTPRequestOperation *op, id response) {
if([self.delegate respondsToSelector:#selector(loginSuccessWithUserName:)]) {
[self.delegate performSelector:#selector(loginSuccessWithUserName:)withObject:self.usernameField.text];
}
[self dismissPopoverController];
}
failure:^(AFHTTPRequestOperation *op, NSError *err) {
NSString* nsLocalizedRecoverySuggestion = [err.userInfo objectForKey:#"NSLocalizedRecoverySuggestion"];
if(err.code == -1009) {
[NSException raise:#"No Internet connection" format:#"It appears you’re not connected to the internet, please configure connectivity."];
}
if([nsLocalizedRecoverySuggestion rangeOfString:#"Wrong username or password."].location != NSNotFound) {
[NSException raise:#"Invalid username or password" format:#"Your given username or password is incorrect"];
}
else {
[NSException raise:#"BSXLoginViewController" format:#"Error during login"];
}
}];
}
#catch (NSException *exception) {
UIAlertView* alert = [[UIAlertView alloc]initWithTitle:#"Login error"
message:exception.description
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
However the exceptions raised in the failure block don't get catched in the catch section.
I kind of understand why it's logical, but i would like to know if there's a way to tell the block that the exceptions happening inside should be handled by the catch section i created.
Thanks for any help!
Sincerely,
Zoli
Don't do this. First of all, and I'm sure you'll get at least a comment from #bbum about this, NSException isn't intended in Objective-C for recoverable errors and propagating recoverable errors through code (see Introduction to Exception Programming Topics for Cocoa). Instead, the construct used in Objective-C is to use NSException basically for unrecoverable programming errors, and to use NSError objects for handing around recoverable errors.
However, you've got a bigger problem here in that the calls that you are making have block callbacks because they return before completing. In this case, your exception handler is exited long before the exceptions are actually thrown.
In this case, I'd suggest removing the exceptions and handling the errors inside of the actual failure: block by dispatching to the main queue and presenting the UIAlert there.
Don't be fooled by the fact that your block is specified inline with other code. You cannot catch exceptions in the block in the outer (non-block) code because the code in the TRY block has already executed (and exited) and the block only executes in it's own scope.
A solution is to catch exceptions in the block.

NSFileHandle writeData: exception handling

This could be rather broad problem but I could not find any online resource addressing or explaining this matter.
The question is after creating NSFileHandle *writer = [NSFileHandle fileHandleForWritingAtPath:"path"] and when you use [writer writedata:"NSData"] there are sine possible exception that could fire according to the apple doc.
"This method raises an exception if the file descriptor is closed or is
not valid, if the receiver represents an unconnected pipe or socket
endpoint, if no free space is left on the file system, or if any other
writing error occurs." - APPLE DOC
All I want to know is is there any way we can handle or validate these issues without using any try catch or checking for each error in a condition check before write. Any possible way we can use NSError to handle this ?
I would say "No". If you did manage to find a test that covered all possible failures before writing, then there is nothing to say that the write operation might fail after this initial test (think about writing to a filesystem with 1KB free and you want to write 4KB).
Therefore wrapping your calls to these methods inside a #try/#catch block would seem to me to be the best approach. These wrappers could then return an NSError ** if you want details of the failure (which you most certainly should want).
- (BOOL)writeData:(NSData *)data
toFileHandle:(NSFileHandle *)fileHandler
error:(NSError **)error
{
#try
{
[fileHandler writeData:data];
}
#catch (NSException *e)
{
if (error != NULL)
{
NSDictionary *userInfo = #{
NSLocalizedDescriptionKey : #"Failed to write data",
// Other stuff?
};
*error = [NSError errorWithDomain:#"MyStuff" code:123 userInfo:userInfo];
}
return NO;
}
return YES;
}
You will certainly want to get the reason for the failure into the NSError, but it's not immediately obvious to me how to go about doing this.

Resources