4. IOS 組件化(蘑菇街的路由+協(xié)議式)

為了研究組件化,我們主要是討論 蘑菇街的路由+協(xié)議式中間件

討論第一種方式涕侈,并參考 蘑菇街IOS組件化 羹奉,我們來實(shí)現(xiàn)一個可以運(yùn)行的demo秒旋,并討論優(yōu)缺點(diǎn)。

路由

MGJRouter 單例尘奏,通過 訂閱或注冊發(fā)布或使用 來實(shí)現(xiàn)滩褥。肯定有點(diǎn)模糊炫加,我們開始代碼化。

確定唯一標(biāo)識

通過mgj://detail?id=:id 注冊铺然,通過 mgj://detail?id=5 傳遞參數(shù)俗孝,首先我們找到兩個url的相同點(diǎn),下面代碼中 我通過一個簡單的算法+ (NSString *)keyWithUrlStr:(NSString *)urlStr, 得到一個 唯一標(biāo)識 mgj_detail_id*, 這樣就可以通過map 來注冊和使用

  • registerURLPattern:toHandler: 注冊
  • openURL: 調(diào)用組件
@interface MGJRouter : NSObject
// 可以在 一個統(tǒng)一的地方來注釋
//mgj://detail?id=:id
+ (void)registerURLPattern:(NSString *)pattern
                 toHandler:(void(^)(NSDictionary *dic))block;
// 去觸發(fā)組件的回調(diào)
//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;
}

// 可以在 一個統(tǒng)一的地方來注釋
+ (void)registerURLPattern:(NSString *)pattern
                 toHandler:(void(^)(NSDictionary *dic))block {
    
    NSString * key = [self keyWithUrlStr:pattern];
    [self shareManager].map[key] = block;
}

// 去觸發(fā)組件的回調(diào)
+ (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
//協(xié)議名 mgj
// host detail
// query  id=:id
// 把 mgj://detail?id=:id 和 mgj://detail?id=5 轉(zhuǎn)變成相同的唯一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) {
            //創(chuàng)建組件魄健,并從字典拿到值
            DetailComposite * detail = [[DetailComposite alloc] init];
            detail.oneId = oneId;
            detail.name  = name;
            // 執(zhí)行組件的方法
            [detail showComposite];
        }
    }];

    // 外界去調(diào)用 執(zhí)行一個組件
    [MGJRouter openURL:@"mgj://detail?id=5&name=leeDev"];
    // 打印出: showComposite _ id = 5 ; name = leeDev

總結(jié)路由功能

其實(shí)就是使用 map 來存儲 key -> 組件的功能 block ,通過 open 傳遞參數(shù)和key 直接調(diào)用這個block赋铝,并傳遞參數(shù)。

協(xié)議 (協(xié)議 - 類)

因?yàn)槲覀兘M件化沽瘦,就是為了不暴露 我們的實(shí)現(xiàn)類革骨,但是我們可以暴露一些接口,這樣其實(shí)就是為了 降低耦合析恋。

蘑菇街是通過 ModuleManager 來管理 協(xié)議 和 類的關(guān)聯(lián)
主要是兩個方法

@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

假設(shè)需要獲取購物車的個數(shù)
我們定義一個協(xié)議

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

在正在實(shí)現(xiàn)類里面去實(shí)現(xiàn)這個協(xié)議

#import "MGjCart.h"
@interface MGJCartImp : NSObject<MGJCart>
@end


@implementation MGJCartImp
+ (NSInteger)orderCount {
    //處理邏輯良哲,并返回結(jié)果
    return 40;
}
@end

注冊和使用


//注冊協(xié)議 我們只需要
    [ModuleManager registerClassName:@"MGJCartImp" forProtocolName:@"MGJCart"];
    
    //從class 獲取的 ,就是我們 只是把 MGJCart 協(xié)議暴露出去
    Class cla = [ModuleManager classForProtocolName:@"MGJCart"];
    NSInteger orderCount = [(id <MGJCart>)cla orderCount];
    NSLog(@"orderCount = %@",@(orderCount));
    // 打印出 orderCount = 40

優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 降低耦合性助隧,就是組件只是依賴url筑凫,而不需要依賴具體的類

缺點(diǎn)

  • 傳遞 image 等對象類型麻煩,url 不支持
  • 回調(diào)block 也很麻煩,是可以通過字典回調(diào)出來巍实,但是需要文檔寫的比較清楚滓技,才能回調(diào)出來
  • 協(xié)議 - 類的 使用,也是比較繁瑣棚潦,一般是該類的實(shí)例是一個 單例對象令漂,因?yàn)檎{(diào)用的都是 + 方法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丸边,一起剝皮案震驚了整個濱河市叠必,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌原环,老刑警劉巖挠唆,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘱吗,居然都是意外死亡玄组,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門谒麦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俄讹,“玉大人,你說我怎么就攤上這事绕德』继牛” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵耻蛇,是天一觀的道長踪蹬。 經(jīng)常有香客問我,道長臣咖,這世上最難降的妖魔是什么跃捣? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮夺蛇,結(jié)果婚禮上疚漆,老公的妹妹穿的比我還像新娘。我一直安慰自己刁赦,他們只是感情好娶聘,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布宠叼。 她就那樣靜靜地躺著吹散,像睡著了一般。 火紅的嫁衣襯著肌膚如雪佑颇。 梳的紋絲不亂的頭發(fā)上宦焦,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天发钝,我揣著相機(jī)與錄音顿涣,去河邊找鬼。 笑死酝豪,一個胖子當(dāng)著我的面吹牛涛碑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播孵淘,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蒲障,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瘫证?” 一聲冷哼從身側(cè)響起揉阎,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎背捌,沒想到半個月后毙籽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毡庆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年坑赡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片么抗。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡毅否,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝇刀,到底是詐尸還是另有隱情螟加,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布吞琐,位于F島的核電站捆探,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏站粟。R本人自食惡果不足惜徐许,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卒蘸。 院中可真熱鬧,春花似錦翻默、人聲如沸缸沃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趾牧。三九已至,卻和暖如春肯污,著一層夾襖步出監(jiān)牢的瞬間翘单,已是汗流浹背吨枉。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哄芜,地道東北人貌亭。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像认臊,于是被迫代替她去往敵國和親圃庭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容