BUG情景: 重復點擊TabBar中的某個 Item 后窟绷,當前頁面中的 UICollectionCell 點擊進入詳情頁面無效锯玛,日志顯示該詳情頁已經 Dealloc 掉了。兼蜈。攘残。
類似點擊 重復點擊 Home 后,進入不了商品詳情頁啦...
GoodsDetailViewController *goodsDetailVC = [[GoodsDetailViewController alloc] init];
goodsDetailVC.goodsId = goodsModel.goodsId;
[self.viewController.navigationController pushViewController:goodsDetailVC animated:YES];
只要一點擊商品Cell为狸,日志就顯示:
GoodsDetailViewController->>>>已經釋放了
PS : 此處是用了一個 Runtime 實現(xiàn)的:
#import "UIViewController+Dealloc.h"
#import <objc/runtime.h>
@implementation UIViewController (Dealloc)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
Method setTextMethod = class_getInstanceMethod(class, NSSelectorFromString(@"dealloc"));
Method replaceSetTextMethod = class_getInstanceMethod(class, NSSelectorFromString(@"pq_dealloc"));
method_exchangeImplementations(setTextMethod, replaceSetTextMethod);
});
}
- (void)pq_dealloc {
NSLog(@"%@->>>>已經釋放了",[self class]);
[self pq_dealloc];
}
@end
一下子很悶歼郭,為什么沒有進入 GoodsDetailViewController ,卻就被釋放掉了?
一辐棒、覺的可能是 TabBarController 那出問題了
因為畢竟此種情況病曾,只有重復點擊 tabbarItem 才出現(xiàn)的,于是對里面進行檢查漾根,發(fā)現(xiàn)就算我將里面完全復原成最基本的情況泰涂,也還是出現(xiàn)這種情況。辐怕。逼蒙。
二、想著是否有 TabBarController 的Category 或者說其他的 分類有影響
在項目中轉了一圈寄疏,發(fā)現(xiàn)是木有的是牢。。陕截。
三妖泄、試著用 Present 換換 Push ,看看會有什么效果
[self.viewController presentViewController:goodsDetailVC animated:YES completion:nil];
發(fā)現(xiàn)是可以的艘策,然后我就在想是不是和 navigationController
有關呢蹈胡? 然后就發(fā)現(xiàn)類似其他的 Push 都不可以進入...
然后這個問題就擴大了,凡是在 tabBar 第一個頁面中朋蔫,重復點擊選中的 tabBarItem 后罚渐,push 相關的頁面都是失效的...
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
viewController 都會被釋放掉...
之后對該方法的攔截全部都看一遍,發(fā)現(xiàn)寫的沒問題啊驯妄,而且這個是在點擊之后才壞的荷并,本來這個方法點擊時有效的,而且在不同 tabBarItem 可以同時呈現(xiàn)兩種不同的情況青扔,例如在 home 中雙擊 home tabBarItem 后源织,該方法失效翩伪;而在Categories tabBarItem 沒有重復點擊卻是好的,只有重復點擊后才失效谈息,顯示進入的 viewController 已經釋放了...
四缘屹、找到源點
經過大半天后,有小伙伴在項目中 UINavigationController 的分類中發(fā)現(xiàn)了這個方法...
+ (void)load {
method_exchangeImplementations(
class_getInstanceMethod(self, @selector(pushViewController:animated:)),
class_getInstanceMethod(self, @selector(safePushViewController: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;
}
}
}
@interface UINavigationController () <UINavigationControllerDelegate>
@property (readwrite,getter = isViewTransitionInProgress) BOOL viewTransitionInProgress;
@end
@implementation UINavigationController (Consistent)
- (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];
}
所以此時再回過頭來看侠仇,就是重復點擊了 tabbarItem 導致 self.isViewTransitionInProgress 變?yōu)閅ES轻姿,而無法繼續(xù)執(zhí)行該方法,從而導致不能 Push 過去逻炊。
重復點擊選中的 tabBarItem 到底為什么會讓該分類中的私有屬性變化呢互亮?
通過日志顯示,第一次點擊 tabbarItem 會被 viewTransitionInProgress 默認設置成 NO余素,重復點擊后 會直接導致 viewTransitionInProgress getter 方法 和 setter 方法被執(zhí)行豹休,其中 setter 方法設置 成 YES。從而下次點擊pushViewController:animated:
的時候桨吊,交換了方法威根,self.isViewTransitionInProgress == YES 就不能進入 [self safePushViewController:viewController animated:animated];
該方法,從而導致不能被執(zhí)行屏积。
PS1: 此處 其中 setter 方法設置 成 YES 是因為該分類中的另一個方法:
- (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];
}
PS2: 注意上面那個屬性可以得出 readwrite
, 默認讀寫的;
getter = isViewTransitionInProgress
修改了 getter 的方法磅甩。
解決
- 1炊林、注釋剛才那個setter 重新設置成YES 的方法:
// if (animated) {
// self.viewTransitionInProgress = YES;
// }
個人認為在 rootViewController,viewTransitionInProgress 應該默認是NO卷要,暫時無發(fā)現(xiàn)有什么問題渣聚。
- 2、另外就是直接干掉這個分類僧叉,因為實際上在該項目中它這個分類用處不是很大奕枝,是起預防的,所以也可以直接不用它瓶堕。
總的說來隘道,下次遇到類似的問題,可以到分類中看看郎笆,有沒有用到 Runtime 的方法谭梗。
另外用Runtime 系列方法也一定要謹慎!