iOS的元件化(模組化)之路

眯大帥發表於2019-03-04

什麼是元件化? 打個比方,一臺電腦由CPU、記憶體、硬碟等元件組成,他們拆卸下來之後放在其他地方也是可以使用的,且CPU與硬碟之間是沒有任何聯絡的。

為什麼要元件化? 而程式碼在慢慢堆積起來之後,許多類之間都存在著“你離不開我,我離不開你”的情況,這就會導致開發效率低下,且容易造成程式碼衝突。其實說白了就是耦合度太高。這樣揉成一坨對測試/編譯/開發效率/後續擴充套件都有一些壞處

每個模組都離不開其他模組,互相依賴粘在一起成為一坨

「元件化」顧名思義就是把一個大的 App 拆成一個個小的元件,相互之間不直接引用。那如何做呢?

元件化


實現方式

理想設計圖,源於微信讀書

照理想設計圖所示,Mediator作為一箇中介軟體起著排程各個模組的作用,那麼Mediator 怎麼去轉發元件間呼叫? 本文將以 JLRoutes 作為Mediator。

在使用JLRoutes之前,請配置scheme,詳見 http://blog.csdn.net/u010127917/article/details/50451251

JLRoutes本質可以理解為:儲存一個全域性的Map,key是url,value是對應的block。這樣在下面的程式碼中:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { 
  return [JLRoutes routeURL:url];
}
複製程式碼

如果自己被開啟:

NSURL *viewUserURL = [NSURL URLWithString:@"myapp://user/view/joeldev"];
[[UIApplication sharedApplication] openURL:viewUserURL];
複製程式碼

JLRoutes就可以遍歷這個全域性的map,通過url來執行對應的block。

廢話不多說,直接上程式碼吧! appdelegate中設定好匹配規則 然後根據傳遞過來的引數進行跳轉

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
//    navigationPush規則
    [JLRoutes addRoute:@"/NaviPush/:controller" handler:^BOOL(NSDictionary<NSString *,NSString *> * _Nonnull parameters) {
//        獲取當前控制器
        UIViewController *currentVc = [self currentViewController];
        UIViewController *v = [[NSClassFromString(parameters[@"controller"]) alloc] init];
        [self paramToVc:v param:parameters];
        
        currentVc.hidesBottomBarWhenPushed = YES;
        [currentVc.navigationController pushViewController:v animated:YES];
        currentVc.hidesBottomBarWhenPushed = NO;
        return YES;
    }];
    //    StoryBoardPush規則
    [JLRoutes addRoute:@"/StoryBoardPush" handler:^BOOL(NSDictionary<NSString *,NSString *> * _Nonnull parameters) {
        //        獲取當前控制器
        UIViewController *currentVc = [self currentViewController];
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:parameters[@"sbname"] bundle:nil];
        UIViewController *v  = [storyboard instantiateViewControllerWithIdentifier:parameters[@"bundleid"]];
        [self paramToVc:v param:parameters];
        
        currentVc.hidesBottomBarWhenPushed = YES;
        [currentVc.navigationController pushViewController:v animated:YES];
        currentVc.hidesBottomBarWhenPushed = NO;
        return YES;
    }];
return YES;
}
複製程式碼

其實在這個環境下不引用任何需要跳轉的控制器來進行引數傳遞是個麻煩的問題, 所以使用runtime來進行引數的傳遞

-(void)paramToVc:(UIViewController *) v param:(NSDictionary<NSString *,NSString *> *)parameters{
    //        runtime將引數傳遞至需要跳轉的控制器
    unsigned int outCount = 0;
    objc_property_t * properties = class_copyPropertyList(v.class , &outCount);
    for (int i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSString *key = [NSString stringWithUTF8String:property_getName(property)];
        NSString *param = parameters[key];
        if (param != nil) {
            [v setValue:param forKey:key];
        }
    }
}
複製程式碼

控制器傳送跳轉規則及引數

-(void)btnClick:(UIButton *) sender{
    if (sender.tag == 0) {
        NSString *customURL = @"TESTDEMO://NaviPush/SecondViewController?userId=99999&age=18";
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
    }else{
        NSString *customURL = @"TESTDEMO://StoryBoardPush?sbname=Main&bundleid=SBVC";
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
    }
}
複製程式碼

乾貨來了!!! https://github.com/sthyuhao/JLRDemo

相關文章