3

The iOS application i took over has a way of handling NSExceptions differently than what i've seen before and wanted to know why it isn't working now.

In the main.m file the old developer has this logic in it:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int retVal = 0;
        @try {
            retVal =  UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        @catch (NSException *exception) {
            //
            //Logic to save Exception in DataStore
            //
            NSLog(@"Exception - %@",[exception description]);
            exit(EXIT_FAILURE);
        }
        return retVal;
    }
}

When the app would get launched again you would receive a prompt to send the exception to us and if you confirmed it would sent it to our server.

I recently pushed an update more optimized for iOS 7 of the application and noticed that i don't get any of these error reports from crashed apps anymore.

So i tested it via the following code which i know gets called:

NSArray *array = [NSArray new];

id object = [array objectAtIndex:4];

To which i receive this:

2014-05-12 14:55:57.575 APPNAME[17989:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds for empty array'
*** First throw call stack:
(0x18ab0b09c 0x196a89d78 0x18aa0c680 0x10007f498 0x18d9e02c0 0x18da997d0 0x18da996cc 0x18da98ba0
 0x18da98840 0x18da98564 0x18da984e4 0x18d9dad78 0x18d5d70cc 0x18d5d1c94 0x18d5d1b4c 
 0x18d5d13d4 0x18d5d1178 0x18d5caa30 0x18aacb7e0 0x18aac8a68 0x18aac8df4 0x18aa09b38 
 0x19042f830 0x18da480e8 0x100036b98 0x197073aa0)
libc++abi.dylib: terminating with uncaught exception of type NSException

As you can see the exception is not being logged or saved but rather it is completely uncaught.

2 Questions:

  1. Is this bad practice? I don't think it is but i am a jr. developer and not really sure and if there is a better way to do this w/o third party service?

  2. Do you know of any changes in iOS 7 that would affect this (UNTOUCHED) Logic?

Rohan Panchal
  • 1,211
  • 1
  • 11
  • 28
  • My guess is Apple now has an exception handler in `UIApplicationMain` or somewhere in the `UIApplication` class – Brad Allred May 12 '14 at 20:39

2 Answers2

10

Is this bad practice? I don't think it is but i am a jr. developer and not really sure and if there is a better way to do this w/o third party service?

Yes, it is bad practice. UIApplicationMain() is a black hole; once control is passed to that function, it is unlikely that any code beyond that call in main() will ever be invoked again.

It is also a naive implementation; it logs less information to stdout than the normal exception handling mechanism (which is the output you are seeing). It hides information that would be useful to debugging and would also, likely, bypass the standard crash reporting mechanism.

Note that there is also a global unhandled exception handling hook. I wouldn't recommend using it, but it does exist.

Do you know of any changes in iOS 7 that would affect this (UNTOUCHED) Logic?

Not off hand, but I haven't looked. Again, though, UIApplicationMain() is a black hole; it doesn't typically return ever.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • I appreciate the answer you gave. I see how this is bad practice as it relies on uIApplicationMain. The logging factor was not an issue because our exception handling dao and reporting classes save a lot of data and include breadcrumbs that we send in as well. It seems that iOS 7 may have changed how it returns because pre-iOS7 they are all reported. – Rohan Panchal May 13 '14 at 16:45
5

According to Exception Programming Topics you can use NSSetUncaughtExceptionHandler function to handle uncaught exceptions. Try the code below:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSSetUncaughtExceptionHandler(handleUncaughtException);
    @throw [NSException exceptionWithName:NSGenericException
                                   reason:@"Test uncaught exception handling"
                                 userInfo:nil];

    return YES;
}

void handleUncaughtException(NSException *exception)
{
    NSLog(@"Exception - %@",[exception description]);
    exit(EXIT_FAILURE);
}
nalexn
  • 10,615
  • 6
  • 44
  • 48
  • I marked this as the right answer because after i asked this question i found this exact answer and it worked. But i have a question as to whether this is good practice? – Rohan Panchal May 13 '14 at 16:43
  • I considered this as a good practice, but I guess we should ask @bbum to explain why he advised not to use it – nalexn May 13 '14 at 17:40