简体   繁体   中英

Replicate Java Try-Catch philosophy in objective-c

I come from a Java background, where try/catch is common practice.

After few months working with objective-c I have never implemented try/catch in my iOS app, because of the nature of the language itself, and general advices for not using it.

Therefore I have always tried to build error free code. But, at time of writing, I still didn't know how a simple thing like that can be translated in objective-c:

// some operation
try {
  // do some work
} catch (SomethingWentWrongException e) {
  // log error, inform user...etc
}
// some more operation and rest of the code

With this code operation around try/catch is executed, but the program is not broke, and the rest of the code after catch is executed.

However there's a rule telling that we shouldn't use try catch for flow control. I would like to implement something similar with objective-c, encapsulate some less important operations that may succeed or not, without breaking the workflow.

How can I do that without objective-c @try ?

thanks

You can do that with Objective-C using @try and @catch (and @finally ). There's no "rule" that says you don't, but there is a pervasive design idiom throughout Cocoa and code build to integrate with Cocoa: exceptions are reserved for programmer error. That means if the person using your API doesn't honour the contract, or doesn't satisfy some preconditions for calling your methods, that is the only time that many Objective-C developers would use exceptions.

The common idiom for handling errors (eg my file went away, I couldn't get the resource I needed etc) in Objective-C code is to use Cocoa's NSError class, passing an instance by reference to the method that could possibly fail. So, rewriting your example:

// some operation
NSError *error;
BOOL itWorked = [object doSomeThingThatCouldFail: &error];
if (!itWorked) {
    // log error, inform user etc.
}
// some more operation and rest of the code

Notice that you check the return value of the method to check whether it succeeded or failed. The error object is guaranteed to be set on failure, but no promise is made about it on success.

The way the implementation of the method works with the error:

- (BOOL)doSomeThingThatCouldFail: (NSError *__autoreleasing*)error {
  //...
  if (!success && error) //check that the user actually supplied an error pointer
  {
    NSDictionary *errorDetails = @{ ... };
    *error = [NSError errorWithDomain: @"Your error domain" code: someInteger userInfo: errorDetails];
  }
  return success;
}

Kind of off topic, but an idiom I've used successfully in several situations where one may need to "abort" an operation in the middle of a series of sub-operations is the following:

int rcode = 0;
do {
    rcode = operationA(xxx);
    if (rcode) break;
    rcode = operationB(xxx);
    if (rcode) break;
    ...
    rcode = operationZ(xxx);
    if (rcode) break;
} while (FALSE);

if (rcode) {
    <do recovery/error-reporting stuff>
}
else {
    <do stuff you'd do if successful>
}

Kind of a poor-man's try/catch -- Avoids the spaghetti logic you'd have if you tried to have an entire if/then/else around each individual operation. (Obviously, you can optionally set some state variables at each step, to know how far you got, what are the reasons for the error, etc.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM