錯(cuò)誤提示如下:
WF: _userSettingsForUser mobile: {
filterBlacklist = (
);
filterWhitelist = (
);
restrictWeb = 1;
useContentFilter = 0;
useContentFilterOverrides = 0;
whitelistEnabled = 0;
}
WF: _WebFilterIsActive returning: NO
WF: _userSettingsForUser mobile: {
filterBlacklist = (
);
filterWhitelist = (
);
restrictWeb = 1;
useContentFilter = 0;
useContentFilterOverrides = 0;
whitelistEnabled = 0;
}
WF: _WebFilterIsActive returning: NO
[Bugly] Trapped uncaught exception 'NSInvalidArgumentException', reason: 'Can't add self as subview' `
這段可以跳過,是我問題出現(xiàn)的方式:
(程序啟動(dòng)后术浪,快速的點(diǎn)擊屏幕瓢对,因?yàn)橛幸粋€(gè)廣告頁,會(huì)跳轉(zhuǎn)廣告頁胰苏,但是在跳轉(zhuǎn)廣告頁之前硕蛹,我會(huì)先切換程序的根控制器,在延時(shí)1秒跳轉(zhuǎn)廣告詳情頁硕并,這時(shí)會(huì)顯示程序的首頁法焰,首頁我做了緩存處理,正好點(diǎn)擊的位置是首頁的滾動(dòng)廣告倔毙,這時(shí)又跳轉(zhuǎn)一個(gè)廣告頁埃仪,最終的結(jié)果是只跳轉(zhuǎn)了時(shí)候首頁的廣告,但是點(diǎn)擊返回的時(shí)候陕赃,無法返回卵蛉,并崩潰,報(bào)如上錯(cuò)誤C纯狻)
現(xiàn)在說一下這個(gè)排查思路:
- 拿這些打印去找度娘傻丝,首先我拿的是
WF: _WebFilterIsActive returning: NO
,(為啥拿這段诉儒,因?yàn)檫@個(gè)打印我沒見過葡缰,比較特殊,我一般都是拿那些不常見的打印去查忱反,你也可以這樣)运准,搜索出來的結(jié)果其中一個(gè)鏈接,問題的矛頭都指向了UIWebview缭受,
AA4A486A-4573-4241-801E-777D6FD7805F.png
解決辦法也很簡單胁澳,就是把UIWebView
更換為WKWebView
,我當(dāng)然按照文檔的指示米者,換好之后韭畸,繼續(xù)測試,發(fā)現(xiàn)問題還是存在 - 既然問題還存在蔓搞,說明不是
UIWebView
的問題胰丁,我把關(guān)注點(diǎn)放在'Can't add self as subview'
這句話上,查下來的結(jié)果認(rèn)為是連續(xù)push兩個(gè)控制器導(dǎo)致喂分,這和我的問題是吻合的锦庸,直接按照文檔的指示開始操作,鏈接
我其實(shí)也看其他人寫的了蒲祈,對(duì)于我來說改起來比較麻煩甘萧,這個(gè)是最簡單的辦法萝嘁,運(yùn)用了運(yùn)行時(shí)!
現(xiàn)在問題完美的解決了扬卷,我也把自己的代碼分享出來牙言,希望幫助遇到同樣問題的你!
下面貼上代碼怪得!
- 首先創(chuàng)建一個(gè)分類(分類名為UINavigationController+SafePushing咱枉,可以隨便起哈)
- 復(fù)制下面的代碼到.m文件
- 創(chuàng)建UINavigationController的時(shí)候引入分類
大功告成!
#import "UINavigationController+SafePushing.h"
#import <objc/runtime.h>
/// This char is used to add storage for the isPushingViewController property.
static char const * const ObjectTagKey = "ObjectTag";
@interface UINavigationController ()<UINavigationControllerDelegate>
@property (readwrite,getter = isViewTransitionInProgress) BOOL viewTransitionInProgress;
@end
@implementation UINavigationController (SafePushing)
- (void)setViewTransitionInProgress:(BOOL)property {
NSNumber *number = [NSNumber numberWithBool:property];
objc_setAssociatedObject(self, ObjectTagKey, number , OBJC_ASSOCIATION_RETAIN);
}
- (BOOL)isViewTransitionInProgress {
NSNumber *number = objc_getAssociatedObject(self, ObjectTagKey);
return [number boolValue];
}
#pragma mark - Intercept Pop, Push, PopToRootVC
/// @name Intercept Pop, Push, PopToRootVC
- (NSArray *)safePopToRootViewControllerAnimated:(BOOL)animated {
if (self.viewTransitionInProgress) return nil;
if (animated) {
self.viewTransitionInProgress = YES;
}
//-- This is not a recursion, due to method swizzling the call below calls the original method.
return [self safePopToRootViewControllerAnimated:animated];
}
- (NSArray *)safePopToViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (self.viewTransitionInProgress) return nil;
if (animated) {
self.viewTransitionInProgress = YES;
}
//-- This is not a recursion, due to method swizzling the call below calls the original method.
return [self safePopToViewController:viewController animated:animated];
}
- (UIViewController *)safePopViewControllerAnimated:(BOOL)animated {
if (self.viewTransitionInProgress) return nil;
if (animated) {
self.viewTransitionInProgress = YES;
}
//-- This is not a recursion, due to method swizzling the call below calls the original method.
return [self safePopViewControllerAnimated:animated];
}
- (void)safePushViewController:(UIViewController *)viewController animated:(BOOL)animated {
self.delegate = self;
//-- If we are already pushing a view controller, we dont push another one.
if (self.isViewTransitionInProgress == NO) {
//-- This is not a recursion, due to method swizzling the call below calls the original method.
[self safePushViewController:viewController animated:animated];
if (animated) {
self.viewTransitionInProgress = YES;
}
}
}
// This is confirmed to be App Store safe.
// If you feel uncomfortable to use Private API, you could also use the delegate method navigationController:didShowViewController:animated:.
- (void)safeDidShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
//-- This is not a recursion. Due to method swizzling this is calling the original method.
[self safeDidShowViewController:viewController animated:animated];
self.viewTransitionInProgress = NO;
}
// If the user doesnt complete the swipe-to-go-back gesture, we need to intercept it and set the flag to NO again.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
id<UIViewControllerTransitionCoordinator> tc = navigationController.topViewController.transitionCoordinator;
[tc notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.viewTransitionInProgress = NO;
//--Reenable swipe back gesture.
self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController;
[self.interactivePopGestureRecognizer setEnabled:YES];
}];
//-- Method swizzling wont work in the case of a delegate so:
//-- forward this method to the original delegate if there is one different than ourselves.
if (navigationController.delegate != self) {
[navigationController.delegate navigationController:navigationController
willShowViewController:viewController
animated:animated];
}
}
+ (void)load {
//-- Exchange the original implementation with our custom one.
method_exchangeImplementations(class_getInstanceMethod(self, @selector(pushViewController:animated:)), class_getInstanceMethod(self, @selector(safePushViewController:animated:)));
// method_exchangeImplementations(class_getInstanceMethod(self, @selector(didShowViewController:animated:)), class_getInstanceMethod(self, @selector(safeDidShowViewController:animated:)));
method_exchangeImplementations(class_getInstanceMethod(self, @selector(popViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopViewControllerAnimated:)));
method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToRootViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopToRootViewControllerAnimated:)));
method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToViewController:animated:)), class_getInstanceMethod(self, @selector(safePopToViewController:animated:)));
}
@end