介紹:
萬能API路由用于iOS框架中,通過指針參數(shù)、KVC、AOP等編程思想,解決程序中的耦合問題, 實現(xiàn)類、實例方法的任意調(diào)用。使用指針入?yún)?,支持基本?shù)據(jù)類型、OC對象類型、結構體、block塊、代理等;通過KVC來實現(xiàn)屬性的動態(tài)賦值操作,實現(xiàn)大型App任意模塊之間的解耦。尤其是解決依賴pod管理開發(fā)的大型組件相互依賴,和不同sdk底層依賴相同庫產(chǎn)生的沖突問題,使得各個sdk完全解耦。
萬能路由API功能:
1.萬能API路由利用AOP編程思想、指針參數(shù)等來實現(xiàn)任意object-c 的API調(diào)用。支持基本數(shù)據(jù)類型、對象類型、代理、block、枚舉、結構體等(系統(tǒng)自帶和自定義均支持)
2.本sdk用于組件化開發(fā)模式,多sdk嵌套等復雜的情況,完全解決項目開發(fā)的耦合度。
組件已開源,地址:https://github.com/Tkoul/TKRouter
pod引入 :? ? ? ? ?pod'TKRouter'
如果找不到,刪除本地pod緩存索引,更新下spec庫即可。
設計背景:
組件開發(fā)模式:很多龐大項目開發(fā),是有多個sdk同時開發(fā)。主App就是一個容器,各個組件開發(fā)完畢,然后進行組合,裝在這個容器上。高內(nèi)聚低耦合,符合軟件設計的標準,完美。
當然組件化開發(fā)并不是這么膚淺,還有組件化開發(fā)的好處這里都不做贅述。網(wǎng)上有很多資料,大的項目離不開組件化的思想。
組件化路由:這樣的開發(fā)模式,效率大大提升,人員分工明確,各個團隊之間的開發(fā)有條不紊。這樣在各個團隊之間的橋梁--路由的作用就不言而喻。常規(guī)的路由,包括目前流行的路由三方組件都有自己的定義規(guī)則,一個項目突然適配起來不是那么簡單。
開發(fā)問題:項目主App,包含多個組件,比如其中一個組件A,一個組件B,分別有倆個團隊負責開發(fā),都有自己完整的流程,那么兩個庫都依賴了AFNetworking 這個請求第三方(大公司會封裝自己的請求框架)。這里依照afnet為例
A單獨開發(fā):A項目,引入 'AFNetworking', '~> 3.0'? 然后 高高興興去開發(fā)了,在項目期限結束的時候,驗證、提交、完事。
B單獨開發(fā):B為老組件,很早就引入 'AFNetworking', '~> 2.0'? 然后 高高興興去開發(fā)了,在項目期限結束的時候,驗證、提交完事。
1.但是當兩個組件進行組合的時候就出現(xiàn)問題了,因為兩個版本不兼容。
可能會有以下兩種解決思路:
方案一:立即聯(lián)系B,告知版本庫升級到3.0用新的,告知所有的團隊以某個版本為準。
方案二:把AFNetworking作為主App的直接bundel內(nèi)容,其它組件去掉AFNetworking
對于方案一:首先如果有100個組件都包含了AFNetworking,50個提供源碼,50個提供的是靜態(tài)庫。那么最后合到主app,就會有51個AFNetworking,這是無法忍受,不可原諒的。如果再有某些大神,靜態(tài)庫打包的時候不給人家加個前綴,合并到主app,就會有很多類似AFNetworking.o這種重復名稱的文件,導致無法運行。
對于方案二:提供源碼的組件,開發(fā)的時候可以導入,提交的時候屏蔽AFNetworking,由于頭文件包含了項目中沒有的庫會提交不上去(此種是使用pod的情況下,如果直接提供源碼到主App的,請忽略這條)。提供靜態(tài)庫的話,如果使用了,但是不包含AFNetworking是打不出包的,更談不上上傳了。
以上問題對組件化開發(fā)App造成很大的困擾,為了解決這個問題,大牛們早就前行在道路上,就出現(xiàn)了“組件二進制化||平滑二進制組件”的實現(xiàn),本人也在使用。原理就是把第三方共用組件比如AFNetworking先做成二進制文件,大家都依賴二進制文件來做到統(tǒng)一。能極大解決問題,弊端就是需要維護很多二進制文件,并且每次升級不同團隊都要做二進制文件的md5哈希取值,這個值一樣才能說明是同一個。每次代碼升級開發(fā)完畢,必須把源碼重新生成新的二進制,維護成本很高,很多時候會有遺漏。
TKRouter使用:
針對諸多的問題,我就開發(fā)了TKRouter。
常規(guī)實現(xiàn):
下面是我的某個組件調(diào)用AFNetworking的網(wǎng)絡檢測代碼:
1. 項目依賴 AFNetworking
2. 實現(xiàn)的地方引入 AFNetworkReachabilityManager.h
3. 實現(xiàn)如下代碼
AFNetworkReachabilityManager *maneage=[AFNetworkReachabilityManager sharedManager];
[maneage startMonitoring];
?[maneage setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
???????? if (status == 0) {
???????????? //無網(wǎng)絡鏈接
? ?????? ?} else {
???????????? //有網(wǎng)鏈接
? ?????? ? }
? ?}];
TKRouter 實現(xiàn):
直接上代碼 ,不要依賴,不需要引入三方的頭文件:
?ReturnStruct? managerStur? = [[[TKRouter router] routerClassName:@"AFNetworkReachabilityManager"]? ? ? ? ?classMethodSelect:@"sharedManager" parameter:nil, nil];
?NSObject *objManager = managerStur.returnValue;
?[objManager? instanceMethodSelect:@"startMonitoring" parameter:nil, nil];
void (^ReachabilityStatusChangeBlock)(NSInteger status) = ^(NSInteger status){
? if (status == 0) {
? //無網(wǎng)絡鏈接
? ?} else {
? //有網(wǎng)鏈接
? ?}
};
?[objManager instanceMethodSelect:@"setReachabilityStatusChangeBlock:" parameter:&ReachabilityStatusChangeBlock, nil];
TKRouter優(yōu)點:
1.調(diào)用原子api ,使用簡單易懂,就像調(diào)用方法一樣。
2.多組件開發(fā),很多組件都依賴某些第三方組件的時候,例如AFNetworking,那么我們就不用考慮依賴的事情了 甚至不用去維護它,直接路由調(diào)用。三方頭文件都不需要引入,想用的時候直接使用即可。
TKRouter是處理主App或者組件中已經(jīng)存在了第三方,其他組件在開發(fā)的時候就能通過TKRouter調(diào)用該三方的工具。其他組件開發(fā)的時候,demo工程需要導入AFNetworking,但是打包和上傳的時候不用包含AFNetworking,不會有報錯、打不出包、上傳不了的問題。依然可與執(zhí)行pod lib lint 和 pod repo push,推送的是組件。想達到實際效果就在demo工程手動導入一下AFNetworking即可。
注意事項:TKRouter 強大的原子調(diào)用毋庸置疑,三方sdk一旦開源!api就固定了,所以主工程種幾百個組件有一個AFNetworking就夠了,因為AFNetworking的api一般不會隨著版本升級而變更,只會里面的實現(xiàn)會有所變更。某個開源庫萬不得已改變了api! 那么由于我們用的路由aop思想編寫出來的程序,api變化,我們組件并沒有報錯,紅點提示。所以每次開源庫大版本升級關注下api變化即可。一般很少遇到!??再說,一般都會迭代幾個版本才會慢慢拋棄一些方法。不要告訴我,你懶到自己代碼寫一遍,一萬年都不再維護吧。??咱們不用關系他升級到第幾個版本,讓擁有這個三方的組件更新維護版本,而我們只關注api!
調(diào)用注意:TKRouter所有的方法參數(shù)為指針類型!就牽涉到左值右值方面的知識。我傳的是左值-內(nèi)存中有實際內(nèi)存的。有興趣的小伙伴可以研究下。簡單起見,如果是方法傳來的值,直接使用會報紅,我們定義一個它的對象,接收一下值,用新定義的對象取地址即可。左值、右值:http://www.itdecent.cn/p/8095517dbb3f
核心方法:
一:
/**
實例子對象 給屬性 賦值
@param propertyParameter 屬性字典組合。? key為屬性的字符串。 value為屬性需要賦予的值
@return 返回
*/
- (ReturnStruct)setPropertyParameter:(NSDictionary*)propertyParameter;
二:
/**
執(zhí)行實例方法
@param selectString 方法名
@param methodParaments 方法參數(shù) --- 指針參數(shù) 對應參數(shù) 以指針類型傳入
@return 返回值
*/
- (ReturnStruct)instanceMethodSelect:(NSString*)selectString parameter:(void *)methodParaments, ... NS_REQUIRES_NIL_TERMINATION;
三:
/**
執(zhí)行類方法
@param selectString 方法名
@param methodParaments 方法參數(shù) --- 指針參數(shù) 對應參數(shù) 以指針類型傳入
@return 返回值
*/
+ (ReturnStruct)classMethodSelect:(NSString*)selectString parameter:(void*)methodParaments, ... NS_REQUIRES_NIL_TERMINATION;
示例:
比如在demo工程:
調(diào)用方法:
+ (NSString*)TestMethodOneWithObjectType:(NSDictionary*)dic andPar:(NSString*)strOne andPar:(NSNumber*)numTwo;
//step 二: AOP 調(diào)用+ 方法。即類方法
Class TKMethodTestClass = [[TKRouter router] routerClassName:@"TKMethodTest"];
NSDictionary *par1 =@{@"key1":@"Hello:TKRouter",@"key2":@"SayHi"};
NSString? ? *par2 = @"字符串類型參數(shù)";
? NSNumber? ? *par3 = [NSNumber numberWithInt:1688];
[TKMethodTestClass classMethodSelect:@"TestMethodOneWithObjectType:andPar:andPar:" parameter:&par1,&par2,&par3, nil];
調(diào)用方法:- (void)TestMethodTwoWithBasicType:(int)numberone? andSecond:(CGFloat)floatTwo;
//step 四-: 實例對象調(diào)用- 方法 - 傳入基本數(shù)據(jù)類型
?NSObject? *object = [[TKRouter router] routerGetInstanceWithClassName:@"TKMethodTest"];
?int? par4 = 8888;
?CGFloat par5 = 88.88;
ReturnStruct returnOne = [object instanceMethodSelect:@"TestMethodTwoWithBasicType:andSecond:"parameter:&par4,&par5, nil];
調(diào)用方法:- (BOOL)TestMethodTwoWithStructType:(CGRect)struOne and:(CGSize)struTwo;
//step 四二: 實例對象調(diào)用- 方法 - 傳入結構體
NSObject? *object = [[TKRouter router]routerGetInstanceWithClassName:@"TKMethodTest"];
CGRect par6 = CGRectMake(100, 100, 200.5, 200);
CGSize par7 = CGSizeMake(666.0, 888.5);
ReturnStruct returnTwo = [object instanceMethodSelect:@"TestMethodTwoWithStructType:and:" parameter:&par6,&par7, nil];
調(diào)用方法:- (NSString*)TestMethodTwoWithBlockType:(void(^)(NSString *str1))block;
//step 四三: 實例對象調(diào)用- 方法 - 傳入block塊
?NSObject? *object = [[TKRouter router]routerGetInstanceWithClassName:@"TKMethodTest"];
void(^parblock8)(NSString *str1) = ^(NSString *str1){
?NSLog(@"\n block 得到的值回調(diào)。==%@\n\n\n",str1);
? ? ? ? ? ? };
ReturnStruct returnThere = [object instanceMethodSelect:@"TestMethodTwoWithBlockType:" parameter:&parblock8, nil];
以上是基本的調(diào)用,更多的去github上download下來可自行查看。(地址:https://github.com/Tkoul/TKRouter)
比如:初始化ctrl,TKRouter給ctrl賦值,TKRouter調(diào)用push,推出新的視圖,TKRouter設置代理!實現(xiàn)基本數(shù)據(jù)類型,結構體,oc類型,block塊,代理等!
如果有幫到你,請去俺的https://github.com/Tkoul/TKRouter地址上 star一下。
歡迎大家交流,email:Tkoull@163.com?