public
Last active

iOS 6 Autorotation Swizzling

  • Download Gist
gistfile1.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
@implementation AppDelegate
void SwapMethodImplementations(Class cls, SEL left_sel, SEL right_sel) {
Method leftMethod = class_getInstanceMethod(cls, left_sel);
Method rightMethod = class_getInstanceMethod(cls, right_sel);
method_exchangeImplementations(leftMethod, rightMethod);
}
 
+ (void)initialize {
if (self == [AppDelegate class]) {
#ifdef __IPHONE_6_0
SwapMethodImplementations([UIViewController class], @selector(supportedInterfaceOrientations), @selector(sp_supportedInterfaceOrientations));
SwapMethodImplementations([UIViewController class], @selector(shouldAutorotate), @selector(sp_shouldAutorotate));
#endif
}
}
@end
 
@implementation UIViewController (iOS6Autorotation)
#ifdef __IPHONE_6_0
/*
* We've swizzled the new iOS 6 autorotation callbacks onto their iOS 5 and iOS 4 equivalents
* to preserve existing functionality.
*
*/
- (BOOL)sp_shouldAutorotate {
BOOL shouldAutorotate = YES;
if ([self respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
NSUInteger mask = 0;
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
mask |= UIInterfaceOrientationMaskPortrait;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) {
mask |= UIInterfaceOrientationMaskLandscapeLeft;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) {
mask |= UIInterfaceOrientationMaskLandscapeRight;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) {
mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
}
if (mask == 0) {
// Shouldn't autorotate to *any* orientation.
shouldAutorotate = NO;
}
} else {
// This actually calls the original method implementation
// instead of recursively calling into this method implementation.
shouldAutorotate = [self sp_shouldAutorotate];
}
return shouldAutorotate;
}
 
- (NSUInteger)sp_supportedInterfaceOrientations {
NSUInteger mask = 0;
/*
* In iOS 6, Apple dramatically changed the way autorotation works.
* Rather than having each view controller respond to shouldAutorotateToInterfaceOrientation:
* to specify whether or not it could support a particular orientation, the responsibility was
* shifted to top-level container view controllers. That means UINavigationController becomes
* responsible for declaring whether or not an orientation is supported. Since our app
* has logic for how to autorotate on a per view controller basis, we call through to the
* swizzled version of supportedInterfaceOrientations for the topViewController.
*
*/
if ([self isKindOfClass:[UINavigationController class]]) {
return [[(UINavigationController *)self topViewController] supportedInterfaceOrientations];
}
if ([self respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
mask |= UIInterfaceOrientationMaskPortrait;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) {
mask |= UIInterfaceOrientationMaskLandscapeLeft;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) {
mask |= UIInterfaceOrientationMaskLandscapeRight;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) {
mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
}
} else {
// This actually calls the original method implementation
// instead of recursively calling into this method implementation.
mask = [self sp_supportedInterfaceOrientations];
}
return mask;
}
#endif
@end

as @davedelong said on twitter: "I love the runtime as much (or more) than the next guy, but you should absolutely not use [this] code."

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.