dgatwood
dgatwood

Reputation: 10417

Is it possible to determine if an Objective-C exception will be caught?

I'm running into a situation in iOS (and OS X) where exceptions from NSKeyedUnarchiver cause binary-only third-party frameworks to crash my app (when deployed in the field) when they try to unarchive a corrupt archive, thus forcing users to delete and reinstall the app. This doesn't happen often, but I'd like that number to be zero.

I can't solve the problem by wrapping the NSKeyedUnarchiver calls, both because I don't have the source code and because those calls are not the direct result of anything that my code does; they run on arbitrary background threads at arbitrary times.

I'm currently swizzling the NSKeyedUnarchiver class so that reading a corrupt archive returns nil (as though the file were not there) rather than throwing an exception, but I can't be certain whether any of those third-party frameworks might do things correctly (with an @try/@catch block) and might break in interesting ways if I do so.

It would be helpful if I could somehow examine the Objective-C exception handling tree (or equivalent) to determine whether an exception handler would catch an exception if thrown, and if so, which handler. That way, my patched method could return nil if the exception would make it all the way up to Crashlytics (which would rethrow it, causing a crash), but could rethrow the exception if some other handler would catch it.

Is such a thing possible, and if so, how?

Upvotes: 2

Views: 444

Answers (2)

creker
creker

Reputation: 9570

If you're not sure that wrapping third-party library code with @try/@catch is good enough you can hook NSKeyedUnarchiver methods to replace them with exact same wrapper thus making sure that exception is never gets thrown outside. Here is pseudo-code:

@try {
  //call original NSKeyedUnarchiver implementation
}
@catch {
  return nil;
}

Objc runtime has public APIs that can do such a thing

Upvotes: 0

Keller
Keller

Reputation: 17081

Why not wrap your exception-throwing callsite in a try/catch/finally?

    @try {
      //call to your third party unarchiver
    }

    @catch {
      //remove your corrupted archive
    }

    @finally {
      //party
    }

Rolling your own global exception handler may also be of use here, ala: How do you implement global iPhone Exception Handling?

Upvotes: 1

Related Questions