- 复现步骤:在UIImagePickController系统相册collection页面上随便长按任意一张图片便会crash
- 复现机型:有3D Touch功能的机型(6s以后的设备)
- 堆栈信息:
Exception Type: EXC_CRASH (SIGABRT)Exception Codes: 0x00000000 at 0x0000000000000000Crashed Thread: 0 Application Specific Information:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSObject previewingContext:viewControllerForLocation:]: unrecognized selector sent to class 0x19f34e020' Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed:0 CoreFoundation __exceptionPreprocess + 1241 libobjc.A.dylib objc_exception_throw + 562 CoreFoundation __CFExceptionProem + 03 UIKit -[UICollectionViewController previewingContext:viewControllerForLocation:] + 1724 UIKit -[_UIViewControllerPreviewSourceViewRecord previewInteractionController:viewControllerForPreviewingAtPosition:inView:presentingViewController:] + 2485 UIKit -[UIPreviewInteractionController startInteractivePreviewAtLocation:inView:] + 2246 UIKit -[UIPreviewInteractionController startInteractivePreviewWithGestureRecognizer:] + 1367 UIKit -[UIPreviewInteractionController _handleRevealGesture:] + 1008 UIKit _UIGestureRecognizerSendTargetActions + 1649 UIKit _UIGestureRecognizerSendActions + 17210 UIKit -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 78411 UIKit ___UIGestureRecognizerUpdate_block_invoke898 + 7212 UIKit _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 37213 UIKit _UIGestureRecognizerUpdate + 240414 UIKit -[UIWindow _sendGesturesForEvent:] + 113215 UIKit -[UIWindow sendEvent:] + 76416 UIKit -[UIApplication sendEvent:] + 24817 UIKit _UIApplicationHandleEventQueue + 552818 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 2419 CoreFoundation __CFRunLoopDoSources0 + 54020 CoreFoundation __CFRunLoopRun + 72421 CoreFoundation CFRunLoopRunSpecific + 38422 GraphicsServices GSEventRunModal + 18023 UIKit UIApplicationMain + 20424 moma main (main.m:15)25 libdyld.dylib start + 4复制代码
-
修复方式:hook
UICollectionViewController
中的previewingContext:viewControllerForLocation:
方法并返回nil即可 -
Code
#import#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(ver) ([[[UIDevice currentDevice] systemVersion] compare:@#ver options:NSNumericSearch] != NSOrderedAscending)#define SYSTEM_VERSION_LESS_THAN(ver) ([[[UIDevice currentDevice] systemVersion] compare:@#ver options:NSNumericSearch] == NSOrderedAscending)@implementation UICollectionViewController (DEF3DTouchCrashFix)+ (void)load{ //经测试iOS 9.3版本不再有该问题 if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(9.0) && SYSTEM_VERSION_LESS_THAN(9.3)) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SEL originalSelector = @selector(previewingContext:viewControllerForLocation:); SEL overrideSelector = @selector(p_previewingContext:viewControllerForLocation:); Method originalMethod = class_getInstanceMethod(self, originalSelector); Method overrideMethod = class_getInstanceMethod(self, overrideSelector); if (!originalMethod) { return; } BOOL success = class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod)); if (success) { class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, overrideMethod); } }); }}- (UIViewController *)p_previewingContext:(id )previewingContext viewControllerForLocation:(CGPoint)location { return nil;}@end复制代码