前言:
上一篇準(zhǔn)備工作組件化開發(fā)之私有庫(kù)制作以及常見(jiàn)問(wèn)題 已經(jīng)說(shuō)明了如何去制作私有庫(kù)并上傳,以及私有庫(kù)podspec文件的一些寫法問(wèn)題,有不清楚的可以通過(guò)上述傳送門去瞅一瞅,這一篇主要寫一下個(gè)人對(duì)于組件化開發(fā)的一些心得和實(shí)戰(zhàn)記錄,后續(xù)會(huì)附上具體demo以供朋友們閱讀,有說(shuō)的不對(duì)的地方也請(qǐng)指出,不要罵我23333,畢竟本人也是菜鳥一枚,自行摸索組件化,難免有些紕漏
體會(huì):
組件化適合多人開發(fā),也是近來(lái)比較熱門的項(xiàng)目架構(gòu)設(shè)計(jì)方式。16年本人便從網(wǎng)上看了些組件化相關(guān)的資料,比較經(jīng)典的是蘑菇街方案蘑菇街App的組件化之路以及蘑菇街的組件化之路.續(xù)和@casatwy基于蘑菇街方案的探討iOS應(yīng)用架構(gòu)談 組件化方案,那時(shí)候看不懂啊,腦袋疼,壓根兒不理解,后來(lái)17年又看了【一縷殤流化隱半邊冰霜】的iOS 組件化 —— 路由設(shè)計(jì)思路分析,以及組件化架構(gòu)漫談 結(jié)果是對(duì)組件化越來(lái)越懵逼,對(duì)于組件化遲遲不敢下手,找不到入口。
最近想要嘗試下組件化到底是一種什么感受,斷斷續(xù)續(xù)看了一年多的組件化理論知識(shí),如今終于要開啟嘗試之旅,心中還是有些忐忑的,于是先去整了私有庫(kù)相關(guān)的一些準(zhǔn)備工作,接下來(lái)嘗試將項(xiàng)目中的一些基礎(chǔ)模塊,公共模塊和功能模塊給抽了出來(lái),算是走出了第一步。
理解:
我個(gè)人對(duì)于組件化的認(rèn)知比較簡(jiǎn)單,覺(jué)得它就是一種解耦的方式,各人管各自的事情,在多人開發(fā)的場(chǎng)景下,這種方式肯定是非常有利于提高開發(fā)效率的,個(gè)人開發(fā)的話有興趣可以嘗試,畢竟是吃力不討好的事情,比如我吃飽了撐的就來(lái)試試~~~
一般項(xiàng)目模塊都是耦合很嚴(yán)重的,如下:

圖中的關(guān)系錯(cuò)綜復(fù)雜,各種耦合,看起來(lái)也是無(wú)可奈何,特別是后期維護(hù),牽一發(fā)而動(dòng)全身,恨不能一鍵刪除推倒重來(lái),這也難不倒思路五花八門的開發(fā)者們,于是為了解耦合,有了下一張圖:

但這個(gè)還有問(wèn)題,雖然各個(gè)模塊之間的耦合解了,但是各個(gè)模塊還要依賴中間件,中間件也要依賴各個(gè)模塊,這還是相當(dāng)于沒(méi)有解耦,所以與時(shí)俱進(jìn),有了下一張圖:

這里表示的是只讓模塊對(duì)中間件依賴,中間件完全不依賴任何模塊,我們所說(shuō)的解耦合其實(shí)也就是這種效果,如果能做到這種,那么,每個(gè)模塊的負(fù)責(zé)人都不用再擔(dān)心另一個(gè)模塊如何,只需要和中間層進(jìn)行溝通即可
對(duì)于中間件,網(wǎng)上流行的有三種用法,一種是蘑菇街的URL方法,一種是target-action硬編碼的方法,另外一種是protocol方法,我個(gè)人采用的是target-action方法,這里就簡(jiǎn)單介紹一下,而后再結(jié)合示例demo具體運(yùn)用。
一.路由-中間件的定制
同樣的,中間件可以作為一個(gè)組件單獨(dú)存在,我這里將以
LWRouter的私有庫(kù)方式去管理路由,里面只提供簡(jiǎn)單的跳轉(zhuǎn)(pushpresent)兩種交互方式
1. 創(chuàng)建路由組件的私有庫(kù),方式參照上篇文章
2. 路由的實(shí)現(xiàn)
+ (UIViewController *)router_getControllerFromClass:(NSString *)classNam {
Class class = NSClassFromString(classNam);
return [[class alloc] init];
}
+ (void)router_jumpToDestination:(UIViewController *)destinationVc from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params {
[self router_jumpToDestination:destinationVc from:sourceVc jumpType:jumpType animation:animation params:params callback:nil];
}
+ (void)router_jumpToDestinationWithName:(NSString *)destination from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params {
UIViewController *destinationVc = [self router_getControllerFromClass:destination];
[self router_jumpToDestination:destinationVc from:sourceVc jumpType:jumpType animation:animation params:params];
}
+ (void)router_jumpToDestinationWithName:(NSString *)destination from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params callback:(void(^)(id callback))callback {
UIViewController *destinationVc = [self router_getControllerFromClass:destination];
[self router_jumpToDestination:destinationVc from:sourceVc jumpType:jumpType animation:animation params:params callback:callback];
}
+ (void)router_jumpToDestination:(UIViewController *)destinationVc from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params callback:(void(^)(id callback))callback {
if (params) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[destinationVc performSelector:@selector(router_params:) withObject:params];
#pragma clang diagnostic pop
}
if (callback) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[destinationVc performSelector:@selector(router_callback:) withObject:callback];
#pragma clang diagnostic pop
}
if (jumpType == YGRouterJumpTypePush) {
[sourceVc.navigationController pushViewController:destinationVc animated:animation];
}else {
[sourceVc presentViewController:destinationVc animated:animation completion:nil];
}
}
這里提供了push ,modal兩種模式,此外還可以傳參以及回傳等,有其他情況的另行增加方法即可
二:示例demo的搭建以及結(jié)合組件化的過(guò)程
示例工程采用tabbar+nav+vc的模式,我這里分為基礎(chǔ)層,網(wǎng)絡(luò)層,應(yīng)用層和業(yè)務(wù)層以及路由。基礎(chǔ)層主要放一些公共部分和變化不大的的部分,網(wǎng)絡(luò)層主要管理項(xiàng)目中間的網(wǎng)絡(luò)請(qǐng)求部分,應(yīng)用層主要是一些工具類的封裝,業(yè)務(wù)層則是項(xiàng)目的一些業(yè)務(wù)邏輯部分,前三層基本不依賴彼此,業(yè)務(wù)層則需要依賴前三層,業(yè)務(wù)層中分為不同的模塊,模塊間的交互通信則是通過(guò)路由,大致的分配如下圖所示:

從圖中可以很清晰的看到,層次劃分非常的清楚,如果多人配合開發(fā),只需要一個(gè)人負(fù)責(zé)一個(gè)模塊即可。至于項(xiàng)目中的哪些可以規(guī)劃到各個(gè)層級(jí)和模塊中就要視具體的情況而定,我這里主要大致說(shuō)一下自己的理解:
1.比如整個(gè)項(xiàng)目中的基類,我這里指的是不變的那些,如導(dǎo)航控制器,這個(gè)一般設(shè)置后就不需要變化的那種,分類,圖片,xib資源,常量類等都可以放到基礎(chǔ)層
2.網(wǎng)絡(luò)層主要放置網(wǎng)絡(luò)請(qǐng)求,可以使離散的,也可以是集約的。集約型也就是對(duì)AFN的二次封裝,提供的只是get,post等接口。離散型的,推薦
YTKNetwork,思想是一個(gè)請(qǐng)求一個(gè)類,這兩者各有優(yōu)劣,關(guān)鍵看個(gè)人取舍。
3.應(yīng)用層主要放一些功能性的文件,如:支付功能,地圖,定位功能,數(shù)據(jù)庫(kù)封裝等
4.業(yè)務(wù)層就是做業(yè)務(wù)功能的,這里可以將每個(gè)模塊細(xì)分為一個(gè)私有庫(kù)方便多人開發(fā)時(shí)每個(gè)人負(fù)責(zé)一個(gè)業(yè)務(wù)模塊去開發(fā)。
5.主工程導(dǎo)入各個(gè)私有庫(kù)文件,提供入口即可
- 大致的結(jié)構(gòu)如此,當(dāng)然這里只是我個(gè)人對(duì)于模塊和層級(jí)的理解,如果你有更好的劃分方式和心得,歡迎在留言區(qū)進(jìn)行溝通交流。
下面具體講下過(guò)程和引入
1.創(chuàng)建遠(yuǎn)程倉(cāng)庫(kù)并拉取到本地,制作成私有庫(kù)


私有庫(kù)的制作見(jiàn)前文,這里不再贅述
最終導(dǎo)入項(xiàng)目的結(jié)構(gòu)如下:


2.主工程調(diào)用
前面已經(jīng)提到,組件化比較理想的結(jié)構(gòu)是,主工程中只有入口,也就是我們常用的設(shè)置TabBar相關(guān)以及一些必要的配置等,其他都在組件私有庫(kù)中完成,通過(guò)上面的結(jié)構(gòu)我們已經(jīng)實(shí)現(xiàn)了拆分功能為私有化組件,接下來(lái)就是通過(guò)主工程提供入口并組合起來(lái)。

3.模塊間的通信與交互
主要通過(guò)router,示例代碼如下:
傳參不帶回傳參數(shù)的:

傳參帶回傳參數(shù)的:

若是ModalA和ModalB交互,采用的方式也是如此
具體的使用過(guò)程可以通過(guò)傳送門查看,有關(guān)于組件化方面的心得體會(huì)可以在評(píng)論區(qū)進(jìn)行交流學(xué)習(xí),本人也是初次嘗試使用,有用的不到的地方或者理解有偏頗的地方,還請(qǐng)海涵,多謝朋友們的指正,大家共同學(xué)習(xí),謝謝~~~~