debugMinor
Unhandled Exception handler that captures a screenshot
Viewed 0 times
exceptioncapturesthatscreenshothandlerunhandled
Problem
So, whether you're still in the development stages or your app is already on the app store, you always hope your app isn't crashing. But if it is, you want to be sure you've got good crash reports, right? Moreover, if your app is on the appstore, it may not be sufficient to wait around for Apple to upload crash reports that iOS automatically generates and submits (for users that have allowed this).
Plus, wouldn't it be nice if your crash reports came with a screenshot (when possible) of what the user saw at the instant of the crash?
This code strives to be able to accomplish some of these things.
First, the relevant parts of class categories:
UIImage+(Screenshot).m
NSDate+(NowString).m
The categories exist merely for convenience, and I am interested in hearing any ways to improve them, however the main code under review is the code that actually handles unhandled exceptions and generates crash logs:
AppDelegate.m
```
#import "AppDelegate.h"
#import "CustomCategories.h"
static NSString * const kKEY_CRASH_REPORT = @"CRASH_REPORT";
static NSString * const kKEY_ExceptionName = @"UnhandledExceptionName";
static NSString * const kKEY_ExceptionReason = @"UnhandledExceptionReason";
static NSString * const kKEY_ExceptionUserInfo = @"UnhandledExceptionUserInfo";
stati
Plus, wouldn't it be nice if your crash reports came with a screenshot (when possible) of what the user saw at the instant of the crash?
This code strives to be able to accomplish some of these things.
First, the relevant parts of class categories:
UIImage+(Screenshot).m
@implementation UIImage (Screenshot)
+ (instancetype)screenshot {
UIWindow *window = [UIApplication sharedApplication].keyWindow;
CGSize windowSize = [window bounds].size;
UIGraphicsBeginImageContext(windowSize);
CGContextRef context = UIGraphicsGetCurrentContext();
[window.layer renderInContext:context];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenshot;
}
@endNSDate+(NowString).m
@implementation NSDate (NowString)
+ (NSString *)nowString {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"YYYY-MM-dd HH:mm:ss zzz"];
return [df stringFromDate:[self date]];
}
@endThe categories exist merely for convenience, and I am interested in hearing any ways to improve them, however the main code under review is the code that actually handles unhandled exceptions and generates crash logs:
AppDelegate.m
```
#import "AppDelegate.h"
#import "CustomCategories.h"
static NSString * const kKEY_CRASH_REPORT = @"CRASH_REPORT";
static NSString * const kKEY_ExceptionName = @"UnhandledExceptionName";
static NSString * const kKEY_ExceptionReason = @"UnhandledExceptionReason";
static NSString * const kKEY_ExceptionUserInfo = @"UnhandledExceptionUserInfo";
stati
Solution
+ (instancetype)screenshot;While it is good to use the
instancetype as your return type to allow for subclass, there are two problems using it here.First, this is a class category, not a class, and the only way for a category to be included in a subclass by default is kind of hacky. You just import the file the category is in in the subclass's header.
But the bigger problem here is this:
// stuff
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
// stuff
return screenshot;The method doesn't actually return a dynamically typed object. It returns a
UIImage object--every time. This method will never return anything other than a UIImage, but through some hacky methods, you could get the IDE to lie and claim it will return SomeUIImageSubclass. The end result though is that the returned object will ALWAYS be a UIImage and never anything else. As such, the declared return type should be changed from instancetype to UIImage:+ (UIImage *)screenshot;Code Snippets
+ (instancetype)screenshot;// stuff
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
// stuff
return screenshot;+ (UIImage *)screenshot;Context
StackExchange Code Review Q#56162, answer score: 8
Revisions (0)
No revisions yet.