iOS --- 使用runtime解决3D Touch导致UIImagePicker崩溃的问题
2016-04-15 02:55
423 查看
3D Touch
3D Touch是iPhone 6s/6splus设备才有的特点, 在系统相册中长按一个照片, 可触发3D Touch相关的操作.
而在没有3D Touch的设备中, 在系统相册中长按一个照片, 会导致crash. 这看起来像是iOS系统的一个bug.
原因在于:
触发3D Touch操作后, PUPhotosGridViewController的previewingContext:viewControllerForLocation:未实现, 所以导致crash.
解决方法:
使用runtime来实现method swizzling, 即在runtime中将该方法替换.
使用method_exchangeImplementations(originalMethod, replacementMethod);方法即可实现.
首先, 封装一个方法用于实现method swizzling
在AppDelegate的application:didFididFinishLaunchingWithOptions:方法中, 进行method swizzling:
3D Touch是iPhone 6s/6splus设备才有的特点, 在系统相册中长按一个照片, 可触发3D Touch相关的操作.
而在没有3D Touch的设备中, 在系统相册中长按一个照片, 会导致crash. 这看起来像是iOS系统的一个bug.
原因在于:
触发3D Touch操作后, PUPhotosGridViewController的previewingContext:viewControllerForLocation:未实现, 所以导致crash.
解决方法:
使用runtime来实现method swizzling, 即在runtime中将该方法替换.
使用method_exchangeImplementations(originalMethod, replacementMethod);方法即可实现.
首先, 封装一个方法用于实现method swizzling
- (void)replaceSelectorForClass:(Class)cls SelectorOriginal:(SEL)original SelectorReplace:(SEL)replacement withBlock:(id)block { IMP implementation = imp_implementationWithBlock(block); Method originalMethod = class_getInstanceMethod(cls, original); class_addMethod(cls, replacement, implementation, method_getTypeEncoding(originalMethod)); Method replacementMethod = class_getInstanceMethod(cls, replacement); if (class_addMethod(cls, original, method_getImplementation(replacementMethod), method_getTypeEncoding(replacementMethod))) { class_replaceMethod(cls, replacement, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, replacementMethod); } }
在AppDelegate的application:didFididFinishLaunchingWithOptions:方法中, 进行method swizzling:
- (void)preventImagePickerCrashOn3DTouch { // Load PhotosUI and bail if 3D Touch is unavailable. // (UIViewControllerPreviewing may be redundant, // as PUPhotosGridViewController only seems to exist on iOS 9, // but I'm being cautious.) NSString *photosUIPath = @"/System/Library/Frameworks/PhotosUI.framework"; NSBundle *photosUI = [NSBundle bundleWithPath:photosUIPath]; Class photosClass = [photosUI classNamed:@"PUPhotosGridViewController"]; if (!(photosClass && objc_getProtocol("UIViewControllerPreviewing"))) { return; } SEL selector = @selector(ab_previewingContext:viewControllerForLocation:); [self replaceSelectorForClass:photosClass SelectorOriginal:@selector(previewingContext:viewControllerForLocation:) SelectorReplace:selector withBlock:^UIViewController *(id self, id<UIViewControllerPreviewing> previewingContext, CGPoint location) { // Default implementation throws on iOS 9.0 and 9.1. @try { // MTLog(@"Replace method at runtime to prevent UIImagePicker crash on 3D Touch."); return ((UIViewController *(*)(id, SEL, id, CGPoint))objc_msgSend)(self, selector, previewingContext, location); } @catch (NSException *e) { return nil; } }]; }
**#import <objc/runtime.h> 如果编译报错 user of undeclared identifier objc_msgSend 选中项目 Build Settings 将ENABLE_STRICT_OBJC_MSGSEND设置为 NO 即可**
相关文章推荐
- Number Sequence(HDU1711)
- BZOJ4527 : K-D-Sequence
- 修改XPMenu让ToolButton在Down=True时正确显示
- ueditor自制上传在ie9中的bug
- GUI之绘制2D贴图
- [LeetCode]60. Permutation Sequence
- 在Html中使用Requirejs进行模块化开发实例详解
- 如何为你的UIView添加边缘分割线
- 去除UITableViewCell左侧分割线15px空白
- iOS中的UIActivityIndicatorView (等待指示器)
- iOS中的UITextView(文本展示框)
- 334_Increasing_Triplet_Subsequence
- IOS博客项目搭建-11-刷新数据UIRefreshControl
- Action View显示UI组件
- RabbitMQ中 exchange、route、queue的关系
- UGUI基础
- 【BFS】HDU1242Rescue
- Android笔记【4】--Android studio issue -->Plugin is too old 滚动显示效果
- APUE(1)----UNIX基础知识
- CodeForces 622A Infinite Sequence