iOS卡顿这个问题本身就是个问题,但有这个问题避免不了万一卡了呢。
在网络少着了很多资料都感觉有些问题,下面是我根据网络上的方案改良一下;
问题描述:
当PUSH一个新的ViewController的时候,不管是init的过于臃肿还是耗时操作没有处理,都有可能导致卡顿;
暴力的测试喜欢狂点,这就出现了同一个ViewController被PUSH了多次
我通过重写导航控制器的方法来解决这个问题。
#import <UIKit/UIKit.h>
@interface YBRNaviViewController : UINavigationController
@end
#import "YBRNavigationController.h"
#import "Aspects.h" //一个可以Hook方法的库
@interface YBRNavigationController ()
<
UINavigationControllerDelegate
>
{
BOOL _pushing;
id<Aspect> _aspect;
}
@end
@implementation YBRNavigationController
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController
{
self = [super initWithRootViewController:rootViewController];
if (self) {
self.delegate = self; //默认代理设置Self
}
return self;
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
//这个地方有个问题,initWithRootViewController会触发pushViewController
if (self.viewControllers.count == 0) {
[super pushViewController:viewController animated:animated];
return;
}
if (_pushing == YES) {
NSLog(@"被拦截 %@",viewController);
return;
}else {
NSLog(@"PUSH %@",viewController);
_pushing = YES;
}
[super pushViewController:viewController animated:animated];
}
- (void)setDelegate:(id<UINavigationControllerDelegate>)delegate {
[super setDelegate:delegate];
//移除_aspect
if (_aspect) {
[_aspect remove];
}
if (delegate && ![self isEqual:delegate]) {
//不是Self
if ([delegate respondsToSelector:@selector(navigationController:didShowViewController:animated:)]) {
//当delegate已经实现 navigationController:didShowViewController:animated: 的时候,
//Hook 该方法
//当然也可以使用 swizzleMethod ,Aspect的API更友好些
__weak __typeof(self)weakSelf = self;
_aspect = [((NSObject *)delegate) aspect_hookSelector:@selector(navigationController:didShowViewController:animated:) withOptions:AspectPositionAfter usingBlock:^(id instance, NSArray *args) {
[weakSelf navigationController:args[0] didShowViewController:args[1] animated:args[2]];
} error:nil];
}else {
//为delegate动态添加 navigationController:didShowViewController:animated:
//不知道有没有这方面的库可以用,只能自己写
Class class = [delegate class];
swizzleMethod(class, @selector(navigationController:didShowViewController:animated:), @selector(navigationController:didShowViewController:animated:));
}
}
}
#pragma mark - UINavigationControllerDelegate
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
_pushing = NO; //完成PUSH
}
@end
///黑魔法
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
{
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}