首屏广告弹屏设计方案

诟病

首页弹窗是用户进来App之后,我们首先要告诉App的最关键的消息, 并且随着业务的更加, 弹窗会越来越多,就会有一下的类似逻辑

<伪代码>

if (弹升级弹窗) {

    if (是否强制升级) {
        // do 弹窗提示
    } else {

        if (弹窗提示用户,用户选择升级) {
            // do 跳转App Store
        } else {
            // 接着走接下来的弹窗逻辑
            // 协议更新弹窗逻辑
            if (协议是否更新) {
                // 更新了,去弹框提示用户阅读最新的用户协议,并同意
                // 同意之后走广告更新逻辑
                if (是否有推广广告) {
                    //  ...
                } else {
                    // ... 
                }
            } else {
                // 广告更新逻辑
                if (是否有推广广告) {
                    // ...
                } else {
                    // ...
                }
            }
        }
    }
}

之后首页的弹窗逻辑将难以维护, 想要去修改弹窗的顺序将难以维护

方案

针对于这种场景使用责任链模式来优化这个问题

最终使用如下

ChainNodeBaseTask *achain = [[AChainNodeTask alloc] init];
ChainNodeBaseTask *bchain = [[BChainNodeTask alloc] init];
ChainNodeBaseTask *cchain = [[CChainNodeTask alloc] init];
// 设定执行顺序
[achain setNextChainNode:bchain];
[bchain setNextChainNode:cchain];
// 预加载
[cchain preperLoad];

self.startTask = achain;
    
    // 开始执行链路头
[achain action];

这样可以随意调节任意一个节点的弹窗实现逻辑和节点的顺序,实现可简单化的增删改查编辑弹窗节点

实现细节:

  1. 定义链路节点协议

/// 首页弹窗链全部执行完成通知
static NSNotificationName const HomeAlertChainAllComplateNotificationKey = @"ChainAllComplateNotificationKey";

/// 定义一个链节点协议
@protocol ChainNodeProtocol 
// 这一块使用strong修饰词是为了拥有下一个节点, 不至于下一个节点过早释放
@property (nonatomic , strong) id < ChainNodeProtocol > nextNode;

// 设置下一个节点
- (void)setNextChainNode:(id )chainNodeObject;
// 开始执行当前节点
- (void)action;
// 当前节点执行完成
- (void)complate;
// 提前准备的事情
- (void)preperLoad;
@end
  1. 实现一个base节点,做一下默认操作
/// 链路节点需要继承的base类,当然也可以不继承,仅仅是少了日志和往下触发事件的代码而已,自己在节点写也是一样
@interface ChainNodeBaseTask : NSObject 

@end

@implementation ChainNodeBaseTask

@synthesize nextNode = _nextNode;

- (void)preperLoad {
    // base里面仅仅做日志输出
    NSLog(@"%@类 弹窗链路准备",NSStringFromClass(self.class));
}

- (void)setNextChainNode:(id)chainNodeObject {
    _nextNode = chainNodeObject;
}

- (void)action {
    // base里面仅仅做日志输出
    NSLog(@"弹窗链路执行到了 %@类",NSStringFromClass(self.class));
    
}

- (void)complate {
    
    if (_nextNode) {
        [_nextNode action];
    } else {
        // base里面仅仅做日志输出
        NSLog(@"弹窗链路执行完毕");
        // 触发完成事件
        [[NSNotificationCenter defaultCenter] postNotificationName:HomeAlertChainAllComplateNotificationKey object:nil];
    }
}

@end
  1. demo简单的示例, 简单的做了3个任务
@interface AChainNodeTask : ChainNodeBaseTask

@end

@implementation AChainNodeTask

- (void)action {
    [super action];
    // 开始网络请求数据,并对结果做处理, 弹窗处理
    
    // 当事情处理完成之后执行完成事件,将链路传到到下一个链路
    [self complate];
}

@end

@interface BChainNodeTask : ChainNodeBaseTask

@end

@implementation BChainNodeTask

- (void)action {
    [super action];
    // 开始网络请求数据,并对结果做处理, 弹窗处理
    
    // 当事情处理完成之后执行完成事件,将链路传到到下一个链路
    [self complate];
}

@end

@interface CChainNodeTask : ChainNodeBaseTask

@property (nonatomic , assign, getter=isActionFlag) BOOL actionFlag;

@end

@implementation CChainNodeTask

- (void)preperLoad {
    // 有可能是比较费时的操作,写在这
    
    // 判断isActionFlag
    if (self.isActionFlag) {
        // 执行弹窗逻辑
    } else {
        self.actionFlag = true;
    }
    
}

- (void)action {
    [super action];
    
    // 判断 preperLoad 是否处理完成, 如果处理完成则进行业务处理, 没有就继续等待执行完成,可能要加标记来处理这个逻辑
    if (self.isActionFlag) {
        // 执行弹窗逻辑
    } else {
        // 根据preperLoad处理的结果进行处理业务逻辑/或者没有处理完成,则什么都不做, 等preperLoad处理完成时候处理弹窗逻辑即可
        self.actionFlag = true;
    }
    
    // 当事情处理完成之后执行完成事件,将链路传到到下一个链路
    [self complate];
}

@end
  1. 实现一个管理类,这样容易不污染其他仓

/// 做一个管理类
@interface ChainTaskManager : NSObject
/// 起始节点
@property (nonatomic,strong)id  startTask;

@end

@implementation ChainTaskManager

+ (instancetype)shared {
    static ChainTaskManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        // 监听弹窗事件链执行结束
        [[NSNotificationCenter defaultCenter] addObserver:instance selector:@selector(alertChainDidEnd) name:HomeAlertChainAllComplateNotificationKey object:nil];
    });
    return instance;
}

- (void)start {

    AChainNodeTask *achain = [[AChainNodeTask alloc] init];
    BChainNodeTask *bchain = [[BChainNodeTask alloc] init];
    CChainNodeTask *cchain = [[CChainNodeTask alloc] init];
    [achain setNextChainNode:bchain];
    [bchain setNextChainNode:cchain];
    // 预加载
    [cchain preperLoad];
    self.startTask = achain;
    
    // 开始执行链路头
    [achain action];
}

- (void)alertChainDidEnd {
    // 释放链路头, 会一次释放所有链路节点
    self.startTask = nil;
}

@end

执行之后输出如下

image-20201221142308175.png

demo地址

你可能感兴趣的:(首屏广告弹屏设计方案)