美文网首页iOS知识点iOS程序员的业余沙龙Swift&Objective-C
iOS 循环push同一种ViewController时,控制数

iOS 循环push同一种ViewController时,控制数

作者: 水暮竹妖 | 来源:发表于2017-07-29 17:35 被阅读1051次

引子

新接手项目有这么个问题,商详页有推荐商品,推荐商品点进去又是商详页,用户可以无限push商详页,产品现在提出需求:只保留第一个产品和最后两个商品。

解决方案

  • 该需求实际是要我们能够自己控制UIViewControllerviewController的顺序。

  • push或者pop实质性操作就是目标VC在对应UINavigationControllerviewControllers的压栈和出栈,通过操作viewControllers就能控制我们想要的VCpop顺序。

  • 对于该需求的解决思路是在push一个商详页的VC后判断是否已经超过连续的三个该VC,如果超过了就将第二个VCviewControllers移除。

代码

  • Demo:
    AZCategory

  • 先看最终怎么使用吧:

//   1.在要限制push次数的VC里添加头文件
#import "UIViewController+PushAndPop.h"

//   2.override下面的方法,返回的即是限制的个数
+ (NSUInteger)cyclePushLimitNumber {
    return 3;
}

  • 我这里是新建了一个UIViewController的一个分类,虽然目前还只是这一个商详页的VC有这个需求,指不定哪天又有其他什么需求了呢【笑。而且商详页这种VC真的是很庞大,还是建议封装的粒度尽量大一点,以及用分类将不同的业务模块拆分到对应的分类中去,不要什么事情都让VC去处理,不然到时候别人看代码以及修改起来都很痛苦【摊手。

  • 代码执行的时机我觉得在viewDidLoad方法里就行了。

  • 设置VC的核心代码其实就一句:

 [self.navigationController setViewControllers:vcsArrM animated:YES];
  • 里面的判断逻辑到时候可以根据需求拓展,分类给VC添加个push&pop规则的ENUM啥的...

  • 完整代码

//  UIViewController+PushAndPop.h
#import <UIKit/UIKit.h>

@interface UIViewController (PushAndPop)
+ (NSUInteger)cyclePushLimitNumber;
@end

//  UIViewController+PushAndPop.m
#import "UIViewController+PushAndPop.h"
#import <objc/runtime.h>

@implementation UIViewController (PushAndPop)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL originalSelector = @selector(viewDidLoad);
        SEL swizzledSelector = @selector(az_viewDidLoad);
        swizzleMethod([self class], originalSelector, swizzledSelector);
    });
}

//  注意下这个 static 
//  关于为啥要在C函数前加static,不知道&有兴趣的可以自己去两个不同的类创建相同的C方法试试:)
static 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);
    }
}

- (void)az_viewDidLoad {
    //   获取limitNum 
    NSUInteger limitNum = [[self class] cyclePushLimitNumber];
    if (limitNum <= 0) { // 0表示不限制数量 
        [self az_viewDidLoad];
        return;
    }
    
    NSArray *vcs = self.navigationController.viewControllers;
    NSMutableArray *productDetailVCIndexArrM = [NSMutableArray array];
    for (NSInteger i = vcs.count; i >= 0; i--) {
        //   从数组尾开始遍历有多少连续的VC
        if (![vcs[i - 1] isKindOfClass:[self class]]) {
            break;
        }
        [productDetailVCIndexArrM addObject:@(i - 1)];
    }
    
    if (productDetailVCIndexArrM.count > limitNum) {
        NSMutableArray *vcsArrM = [vcs mutableCopy];
        [vcsArrM removeObjectAtIndex:[productDetailVCIndexArrM[1] integerValue]];
        [self.navigationController setViewControllers:vcsArrM animated:YES];
    }
    [self az_viewDidLoad];
}

+ (NSUInteger)cyclePushLimitNumber {
    return 0;
}

@end

相关文章

网友评论

  • 李某lkb:产品现在提出需求:只保留第一个产品和最后两个商品. 一个需求累死人
  • 88c862862018:SEL originalSelector = @selector(viewDidLoad);
    SEL swizzledSelector = @selector(az_viewDidLoad);
    swizzleMethod([self class], originalSelector, swizzledSelector);
    不使用dispatchonce,如果只想执行一次,能否放到initialize方法里?
    水暮竹妖:@广羽人三_ load方法其实也只会执行一次,而且load相比较initialize的加载时机更加靠前,比较适合放方法替换这种代码
  • 那根经痛了:是真的很好了 学习学习

本文标题:iOS 循环push同一种ViewController时,控制数

本文链接:https://www.haomeiwen.com/subject/busclxtx.html