Skip to content

Instantly share code, notes, and snippets.

@steipete
Last active January 27, 2020 04:32
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steipete/b00fc02aa9f1c66c11d0f996b1ba1265 to your computer and use it in GitHub Desktop.
Save steipete/b00fc02aa9f1c66c11d0f996b1ba1265 to your computer and use it in GitHub Desktop.
UIKit has two places where it tries to present an action sheet on the rootViewController when it should present things on the topmost presentedViewController. This is our attempt of the least horrible workaround to fix this issue. (http://www.openradar.me/26295020).
#warning This still misses safeguards and has private API references in it. Use only when you really know what you're doing!
// pspdf_swizzleSelectorWithBlock not provided. Use your swizzling helper of choice
// (e.g. http://petersteinberger.com/blog/2014/a-story-about-swizzling-the-right-way-and-touch-forwarding/)
// Fixes rdar://26295020
static void PSPDFInstallWorkaroundForSheetPresentationIssue26295020(void) {
__block auto removeWorkaround = ^{};
const auto installWorkaround = ^{
const SEL presentSEL = @selector(presentViewController:animated:completion:);
__block IMP origIMP = pspdf_swizzleSelectorWithBlock(UIViewController.class, presentSEL, ^(UIViewController *self, id vC, BOOL animated, id completion) {
UIViewController *targetVC = self;
while (targetVC.presentedViewController) {
targetVC = targetVC.presentedViewController;
}
((void (*)(id, SEL, id, BOOL, id))origIMP)(targetVC, presentSEL, vC, animated, completion);
});
removeWorkaround = ^{
pspdf_swizzleSelector(UIViewController.class, presentSEL, origIMP);
};
};
const SEL presentSheetSEL = NSSelectorFromString(@"presentSheetFromRect:");
const auto swizzleOnClass = ^(Class klass) {
const __block IMP origIMP = pspdf_swizzleSelectorWithBlock(klass, presentSheetSEL, ^(id self, CGRect rect) {
// Before calling the original implementation, we swizzle the presentation logic on UIViewController
installWorkaround();
// UIKit later presents the sheet on [view.window rootViewController];
// See https://github.com/WebKit/webkit/blob/1aceb9ed7a42d0a5ed11558c72bcd57068b642e7/Source/WebKit2/UIProcess/ios/WKActionSheet.mm#L102
// Our workaround forwards this to the topmost presentedViewController instead.
((void (*)(id, SEL, CGRect))origIMP)(self, presentSheetSEL, rect);
// Cleaning up again - this workaround would swallow bugs if we let it be there.
removeWorkaround();
});
};
swizzleOnClass(NSClassFromString(@"_UIRotatingAlertController"));
swizzleOnClass(NSClassFromString(@"WKActionSheet"));
}
@tamastimar
Copy link

(...) has private API references in it.

Is it safe for your SDK customers?

@MaximusMcCann
Copy link

Anyone have a Swift version here?

@steipete
Copy link
Author

steipete commented Feb 4, 2017

@tamastimar Yes, a variant of this solution ships in thousands of apps.
@MaximusMcCann: This is just trickier and uglier in Swift, simply use the ObjC variant, the languages mix very well and after all, you apply the patch to a pure ObjC(++) framework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment