meow
meow

Reputation: 28164

Creating a standard try-catch-block for use through the application

I am building a app with many different parts which access remote API calls (both my own, and others). There are many errors that might happen, and to exacerbate the problem, different libraries handle these errors differently.

Essentially, I would like to use the same error handling blocks for all these remote calls.

This is how I would do it with Ruby, but I am not that sure how to manipulate Objective-C in the same manner:

  //universal function to handle standard remote errors across errors
  def universal_handling
    begin
      yield
    rescue Exception => e
      // handle different exceptions accordingly  
      // allow crash if unexpected exception
    end
  end

  //how I would use the above block
  universal_handling{  //any of my remote call here  }

So, I have two questions:

  1. How would I write the equivalent code in Objective-C? It is critical that I can use the same handling block throughout the app
  2. In iOS dev, is this good practice?

I am interested in seeing example code. Error handling can be a major pain, so I want to get this right early on.

Notes:

  1. Blocks are perfectly fine. I am not intending to support < 4.2 versions.
  2. I read most of the articles out there, but none answers how you can use blocks to write "wrappers" for a specific set of calls.

Upvotes: 1

Views: 565

Answers (2)

Barry Wark
Barry Wark

Reputation: 107754

You can do something very similar with blocks:

typedef void(^WrappableBlock)(void);

^(WrappableBlock block) {
  @try {
    block();
  }
  @catch(...)
  }
    //handle exception
  }
}

However, it's very important to realize that the Cocoa (and CocoaTouch) libraries are not exception-safe. Throwing an exception through Cocoa frameworks will lead to all sorts of problems as the frameworks will not properly handle or clean up from the exceptions, leaving your application in a possibly inconsistent state. The correct Cocoa-style is to use NSError and return flags to indicate error conditions. This is neither better nor worse than using exceptions, just a different philosophy.

To do something similar to your universal_handling with NSError is not quite so straight forward because it will require that anything you call comply with the NSError pattern. That said:

typedef BOOL(^WrappableBlock)(NSError**);

^(WrappableBlock block, NSError **err) {
  BOOL success = block(err);
  if(!success) {
    // handle error
  }

  return success;
}

would wrap any method that takes just an NSError** and returns a BOOL to indicate the presence of an error. Obviously the utility of this wrapper is limited as you'll have to wrap any interesting method in an other block to handle any other parameters. Of course, since it's the NSError** pattern, you can always just handle the errors when/where you want and pass NULL as the NSError** parameter where you don't care (ignoring the return value).

One final note: if you are using libraries that may throw exceptions, you must catch those exceptions within the scope of the library call and handle them. Do not let the exceptions propagate as they might then propagate through Cocoa framework code. Thus, the utility of the universal_handling block you propose is limited.

Upvotes: 5

Vincent Guerci
Vincent Guerci

Reputation: 14419

I would suggest you this nice cocoawithlove article that explains how to handle unhandled exceptions in Objective-C and also how to recover from an exception instead of "just" crashing. That could be a good alternative to what you are looking for.

I'm afraid that Objective-C not being as dynamic as ruby, that is a bit harder to do.

Would love to see a good block based implementation too, if that's possible, even If I'm not using them yet, because of previous version compatibility.

Upvotes: 0

Related Questions