在iOS13中,系统对在子线程进行UI操作做了更加严格的检验,会直接抛出 threading violation: expected the main thread 。该问题在真实项目中,我们对堆栈信息中的 [UIDevice endGeneratingDeviceOrientationNotifications] 进行 hook 处理,通过 Crash必现的路径,看到这个方法会发生在子线程中:
@implementation UIDevice (PG)
static inline void pg_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
+ (void)load {
if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
pg_swizzleSelector(UIDevice.class, @selector(endGeneratingDeviceOrientationNotifications), @selector(pgEndGeneratingDeviceOrientationNotifications));
}
}
- (void)pgEndGeneratingDeviceOrientationNotifications {
NSLog(@"pgEndGeneratingDeviceOrientationNotifications isMainThread:%d", [NSThread isMainThread]);
[self pgEndGeneratingDeviceOrientationNotifications];
}
@end
hook [UIDevice endGeneratingDeviceOrientationNotifications] 判断执行该方法是否在主线程中执行,如果不是,则同步到主线程中转发: (最终代码)
@implementation UIDevice (PG)
static inline void pg_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
+ (void)load {
if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
pg_swizzleSelector(UIDevice.class, @selector(endGeneratingDeviceOrientationNotifications), @selector(pgEndGeneratingDeviceOrientationNotifications));
}
}
- (void)pgEndGeneratingDeviceOrientationNotifications {
NSLog(@"pgEndGeneratingDeviceOrientationNotifications isMainThread:%d", [NSThread isMainThread]);
[self pgEndGeneratingDeviceOrientationNotifications];
}
@end
问题结束了?
上面的问题解决,其实的确是能解决问题,但是并没有从根源上发现到底是什么地方导致,通过查看代码发现,我们的项目中对 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications] 、[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications] 没有成对实现,测试发现,如果 多调用了两次 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications] , 然后再唤起H5的拍照/录视频,在iOS13系统上必然Crash,可以在下载 HDCameraCrashDemo 进行验证
可以在 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications] 、[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications] 添加一个 BOOL 类型的变量来控制他们的成对出现,从根本上解决这类问题。
所以这个并不一定是iOS13系统的问题,只要在调用系统方法合理,并不会有该类型的Crash发生。
————————————————
原作者戳链接:https://blog.csdn.net/u012390519/article/details/103680390
网友评论