美文网首页iOS学习
4. IOS 组件化(蘑菇街的路由+协议式)

4. IOS 组件化(蘑菇街的路由+协议式)

作者: LeeDev | 来源:发表于2019-08-15 14:49 被阅读0次

    为了研究组件化,我们主要是讨论 蘑菇街的路由+协议式中间件

    讨论第一种方式,并参考 蘑菇街IOS组件化 ,我们来实现一个可以运行的demo,并讨论优缺点。

    路由

    MGJRouter 单例,通过 订阅或注册发布或使用 来实现。肯定有点模糊,我们开始代码化。

    确定唯一标识

    通过mgj://detail?id=:id 注册,通过 mgj://detail?id=5 传递参数,首先我们找到两个url的相同点,下面代码中 我通过一个简单的算法+ (NSString *)keyWithUrlStr:(NSString *)urlStr, 得到一个 唯一标识 mgj_detail_id*, 这样就可以通过map 来注册和使用

    • registerURLPattern:toHandler: 注册
    • openURL: 调用组件
    @interface MGJRouter : NSObject
    // 可以在 一个统一的地方来注释
    //mgj://detail?id=:id
    + (void)registerURLPattern:(NSString *)pattern
                     toHandler:(void(^)(NSDictionary *dic))block;
    // 去触发组件的回调
    //mgj://detail?id=5
    + (void)openURL:(NSString *)urlStr;
    @end
    
    @interface MGJRouter()
    
    @property (nonatomic,strong) NSMutableDictionary * map;
    
    @end
    
    @implementation MGJRouter
    
    - (instancetype)init {
        if (self = [super init]) {
            self.map = [NSMutableDictionary dictionary];
        }
        return self;
    }
    
    + (MGJRouter *)shareManager {
        static dispatch_once_t onceToken;
        static MGJRouter * router = nil;
        dispatch_once(&onceToken, ^{
            if (router == nil) {
                router = [[MGJRouter alloc] init];
            }
        });
        return router;
    }
    
    // 可以在 一个统一的地方来注释
    + (void)registerURLPattern:(NSString *)pattern
                     toHandler:(void(^)(NSDictionary *dic))block {
        
        NSString * key = [self keyWithUrlStr:pattern];
        [self shareManager].map[key] = block;
    }
    
    // 去触发组件的回调
    + (void)openURL:(NSString *)urlStr {
        
        NSString * key = [self keyWithUrlStr:urlStr];
        NSLog(@"key = %@",key);
        void(^block)(NSDictionary *dic) = [self shareManager].map[key];
        if (block) {
            NSMutableDictionary * param  = nil;
            NSURL * url = [NSURL URLWithString:urlStr];
            NSString * query = url.query;
            if (query.length) {
                NSArray * items = [query componentsSeparatedByString:@"&"];
                param = [NSMutableDictionary dictionary];
                for (NSString * item in items) {
                    NSArray * littleItems = [item componentsSeparatedByString:@"="];
                    NSString * itemFirst = littleItems.firstObject;
                    NSString * itemSecond = littleItems.lastObject;
                    if (itemFirst && itemSecond) {
                        param[itemFirst] = itemSecond;
                    }
                }
            }
            block(param);
        }
    }
    
    
    //mgj://detail?id=:id
    //协议名 mgj
    // host detail
    // query  id=:id
    // 把 mgj://detail?id=:id 和 mgj://detail?id=5 转变成相同的唯一key
    + (NSString *)keyWithUrlStr:(NSString *)urlStr {
        NSURL * url = [NSURL URLWithString:urlStr];
        NSString * query = url.query;
        NSString * queryStr = @"";
        if (query.length) {
            NSArray * items = [query componentsSeparatedByString:@"&"];
            for (NSString * item in items) {
                NSString * itemFirst = [item componentsSeparatedByString:@"="].firstObject;
                queryStr = [queryStr stringByAppendingString:itemFirst];
                queryStr = [queryStr stringByAppendingString:@"*"];
            }
        }
        return [NSString stringWithFormat:@"%@_%@_%@",url.scheme,url.host,queryStr];
    }
    
    @end
    
    

    测试组件

    // 注册一个组件(一般在启动的时候去注册)
        [MGJRouter registerURLPattern:@"mgj://detail?id=:id&name=:name" toHandler:^(NSDictionary *dic) {
            NSString * oneId = dic[@"id"];
            NSString * name  = dic[@"name"];
            if (oneId && name) {
                //创建组件,并从字典拿到值
                DetailComposite * detail = [[DetailComposite alloc] init];
                detail.oneId = oneId;
                detail.name  = name;
                // 执行组件的方法
                [detail showComposite];
            }
        }];
    
        // 外界去调用 执行一个组件
        [MGJRouter openURL:@"mgj://detail?id=5&name=leeDev"];
        // 打印出: showComposite _ id = 5 ; name = leeDev
    

    总结路由功能

    其实就是使用 map 来存储 key -> 组件的功能 block ,通过 open 传递参数和key 直接调用这个block,并传递参数。

    协议 (协议 - 类)

    因为我们组件化,就是为了不暴露 我们的实现类,但是我们可以暴露一些接口,这样其实就是为了 降低耦合。

    蘑菇街是通过 ModuleManager 来管理 协议 和 类的关联
    主要是两个方法

    @interface ModuleManager : NSObject
    + (void)registerClassName:(NSString *)className forProtocolName:(NSString *)protocolName;
    + (Class)classForProtocolName:(NSString *)protocolName;
    @end
    
    
    
    @interface ModuleManager()
    
    @property (nonatomic,strong) NSMutableDictionary * map;
    
    @end
    @implementation ModuleManager
    
    
    - (instancetype)init {
        if (self = [super init]) {
            self.map = [NSMutableDictionary dictionary];
        }
        return self;
    }
    
    + (ModuleManager *)shareManager {
        static dispatch_once_t onceToken;
        static ModuleManager * router = nil;
        dispatch_once(&onceToken, ^{
            if (router == nil) {
                router = [[ModuleManager alloc] init];
            }
        });
        return router;
    }
    
    + (void)registerClassName:(NSString *)className forProtocolName:(NSString *)protocolName {
        
        [self shareManager].map[protocolName] = className;
    }
    
    + (Class)classForProtocolName:(NSString *)protocolName {
        
        NSString * className = [self shareManager].map[protocolName];
        return NSClassFromString(className);
    }
    
    @end
    
    

    假设需要获取购物车的个数
    我们定义一个协议

    @protocol MGJCart <NSObject>
    + (NSInteger)orderCount;
    @end
    

    在正在实现类里面去实现这个协议

    #import "MGjCart.h"
    @interface MGJCartImp : NSObject<MGJCart>
    @end
    
    
    @implementation MGJCartImp
    + (NSInteger)orderCount {
        //处理逻辑,并返回结果
        return 40;
    }
    @end
    

    注册和使用

    
    //注册协议 我们只需要
        [ModuleManager registerClassName:@"MGJCartImp" forProtocolName:@"MGJCart"];
        
        //从class 获取的 ,就是我们 只是把 MGJCart 协议暴露出去
        Class cla = [ModuleManager classForProtocolName:@"MGJCart"];
        NSInteger orderCount = [(id <MGJCart>)cla orderCount];
        NSLog(@"orderCount = %@",@(orderCount));
        // 打印出 orderCount = 40
    
    

    优缺点

    优点

    • 降低耦合性,就是组件只是依赖url,而不需要依赖具体的类

    缺点

    • 传递 image 等对象类型麻烦,url 不支持
    • 回调block 也很麻烦,是可以通过字典回调出来,但是需要文档写的比较清楚,才能回调出来
    • 协议 - 类的 使用,也是比较繁琐,一般是该类的实例是一个 单例对象,因为调用的都是 + 方法

    相关文章

      网友评论

        本文标题:4. IOS 组件化(蘑菇街的路由+协议式)

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