万能API路由(api任意调用,组件完全解耦)-iOS

介绍:

万能API路由用于iOS框架中,通过指针参数、KVC、AOP等编程思想,解决程序中的耦合问题, 实现类、实例方法的任意调用。使用指针入参,支持基本数据类型、OC对象类型、结构体、block块、代理等;通过KVC来实现属性的动态赋值操作,实现大型App任意模块之间的解耦。尤其是解决依赖pod管理开发的大型组件相互依赖,和不同sdk底层依赖相同库产生的冲突问题,使得各个sdk完全解耦。

万能路由API功能:

1.万能API路由利用AOP编程思想、指针参数等来实现任意object-c 的API调用。支持基本数据类型、对象类型、代理、block、枚举、结构体等(系统自带和自定义均支持)

2.本sdk用于组件化开发模式,多sdk嵌套等复杂的情况,完全解决项目开发的耦合度。

组件已开源,地址:https://github.com/Tkoul/TKRouter

pod引入 :         pod'TKRouter'

如果找不到,删除本地pod缓存索引,更新下spec库即可。

设计背景:

组件开发模式:很多庞大项目开发,是有多个sdk同时开发。主App就是一个容器,各个组件开发完毕,然后进行组合,装在这个容器上。高内聚低耦合,符合软件设计的标准,完美。

当然组件化开发并不是这么肤浅,还有组件化开发的好处这里都不做赘述。网上有很多资料,大的项目离不开组件化的思想。

组件化路由:这样的开发模式,效率大大提升,人员分工明确,各个团队之间的开发有条不紊。这样在各个团队之间的桥梁--路由的作用就不言而喻。常规的路由,包括目前流行的路由三方组件都有自己的定义规则,一个项目突然适配起来不是那么简单。

开发问题:项目主App,包含多个组件,比如其中一个组件A,一个组件B,分别有俩个团队负责开发,都有自己完整的流程,那么两个库都依赖了AFNetworking 这个请求第三方(大公司会封装自己的请求框架)。这里依照afnet为例

A单独开发:A项目,引入 'AFNetworking', '~> 3.0'  然后 高高兴兴去开发了,在项目期限结束的时候,验证、提交、完事。

B单独开发:B为老组件,很早就引入 'AFNetworking', '~> 2.0'  然后 高高兴兴去开发了,在项目期限结束的时候,验证、提交完事。

1.但是当两个组件进行组合的时候就出现问题了,因为两个版本不兼容。

可能会有以下两种解决思路:

方案一:立即联系B,告知版本库升级到3.0用新的,告知所有的团队以某个版本为准。

方案二:把AFNetworking作为主App的直接bundel内容,其它组件去掉AFNetworking

对于方案一:首先如果有100个组件都包含了AFNetworking,50个提供源码,50个提供的是静态库。那么最后合到主app,就会有51个AFNetworking,这是无法忍受,不可原谅的。如果再有某些大神,静态库打包的时候不给人家加个前缀,合并到主app,就会有很多类似AFNetworking.o这种重复名称的文件,导致无法运行。

对于方案二:提供源码的组件,开发的时候可以导入,提交的时候屏蔽AFNetworking,由于头文件包含了项目中没有的库会提交不上去(此种是使用pod的情况下,如果直接提供源码到主App的,请忽略这条)。提供静态库的话,如果使用了,但是不包含AFNetworking是打不出包的,更谈不上上传了。

以上问题对组件化开发App造成很大的困扰,为了解决这个问题,大牛们早就前行在道路上,就出现了“组件二进制化||平滑二进制组件”的实现,本人也在使用。原理就是把第三方共用组件比如AFNetworking先做成二进制文件,大家都依赖二进制文件来做到统一。能极大解决问题,弊端就是需要维护很多二进制文件,并且每次升级不同团队都要做二进制文件的md5哈希取值,这个值一样才能说明是同一个。每次代码升级开发完毕,必须把源码重新生成新的二进制,维护成本很高,很多时候会有遗漏。

TKRouter使用:

针对诸多的问题,我就开发了TKRouter。

常规实现:

下面是我的某个组件调用AFNetworking的网络检测代码:

1. 项目依赖 AFNetworking

2. 实现的地方引入 AFNetworkReachabilityManager.h

3. 实现如下代码

AFNetworkReachabilityManager *maneage=[AFNetworkReachabilityManager sharedManager];

[maneage startMonitoring];

 [maneage setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

         if (status == 0) {

             //无网络链接

          } else {

             //有网链接

           }

   }];

TKRouter 实现:

直接上代码 ,不要依赖,不需要引入三方的头文件:

 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) {

  //无网络链接

   } else {

  //有网链接

   }

};

 [objManager instanceMethodSelect:@"setReachabilityStatusChangeBlock:" parameter:&ReachabilityStatusChangeBlock, nil];

TKRouter优点:

1.调用原子api ,使用简单易懂,就像调用方法一样。

2.多组件开发,很多组件都依赖某些第三方组件的时候,例如AFNetworking,那么我们就不用考虑依赖的事情了 甚至不用去维护它,直接路由调用。三方头文件都不需要引入,想用的时候直接使用即可。

TKRouter是处理主App或者组件中已经存在了第三方,其他组件在开发的时候就能通过TKRouter调用该三方的工具。其他组件开发的时候,demo工程需要导入AFNetworking,但是打包和上传的时候不用包含AFNetworking,不会有报错、打不出包、上传不了的问题。依然可与执行pod lib lint 和 pod repo push,推送的是组件。想达到实际效果就在demo工程手动导入一下AFNetworking即可。

注意事项:TKRouter 强大的原子调用毋庸置疑,三方sdk一旦开源!api就固定了,所以主工程种几百个组件有一个AFNetworking就够了,因为AFNetworking的api一般不会随着版本升级而变更,只会里面的实现会有所变更。某个开源库万不得已改变了api! 那么由于我们用的路由aop思想编写出来的程序,api变化,我们组件并没有报错,红点提示。所以每次开源库大版本升级关注下api变化即可。一般很少遇到!😄再说,一般都会迭代几个版本才会慢慢抛弃一些方法。不要告诉我,你懒到自己代码写一遍,一万年都不再维护吧。😄咱们不用关系他升级到第几个版本,让拥有这个三方的组件更新维护版本,而我们只关注api!

调用注意:TKRouter所有的方法参数为指针类型!就牵涉到左值右值方面的知识。我传的是左值-内存中有实际内存的。有兴趣的小伙伴可以研究下。简单起见,如果是方法传来的值,直接使用会报红,我们定义一个它的对象,接收一下值,用新定义的对象取地址即可。左值、右值:https://www.jianshu.com/p/8095517dbb3f

核心方法:

一:

/**

实例子对象 给属性 赋值

@param propertyParameter 属性字典组合。  key为属性的字符串。 value为属性需要赋予的值

@return 返回

*/

- (ReturnStruct)setPropertyParameter:(NSDictionary*)propertyParameter;

二:

/**

执行实例方法

@param selectString 方法名

@param methodParaments 方法参数 --- 指针参数 对应参数 以指针类型传入

@return 返回值

*/

- (ReturnStruct)instanceMethodSelect:(NSString*)selectString parameter:(void *)methodParaments, ... NS_REQUIRES_NIL_TERMINATION;

三:

/**

执行类方法

@param selectString 方法名

@param methodParaments 方法参数 --- 指针参数 对应参数 以指针类型传入

@return 返回值

*/

+ (ReturnStruct)classMethodSelect:(NSString*)selectString parameter:(void*)methodParaments, ... NS_REQUIRES_NIL_TERMINATION;

示例:

比如在demo工程:

调用方法:

+ (NSString*)TestMethodOneWithObjectType:(NSDictionary*)dic andPar:(NSString*)strOne andPar:(NSNumber*)numTwo;

//step 二: AOP 调用+ 方法。即类方法

Class TKMethodTestClass = [[TKRouter router] routerClassName:@"TKMethodTest"];

NSDictionary *par1 =@{@"key1":@"Hello:TKRouter",@"key2":@"SayHi"};

NSString    *par2 = @"字符串类型参数";

  NSNumber    *par3 = [NSNumber numberWithInt:1688];

[TKMethodTestClass classMethodSelect:@"TestMethodOneWithObjectType:andPar:andPar:" parameter:&par1,&par2,&par3, nil];

调用方法:- (void)TestMethodTwoWithBasicType:(int)numberone  andSecond:(CGFloat)floatTwo;

//step 四-: 实例对象调用- 方法 - 传入基本数据类型

 NSObject  *object = [[TKRouter router] routerGetInstanceWithClassName:@"TKMethodTest"];

 int  par4 = 8888;

 CGFloat par5 = 88.88;

ReturnStruct returnOne = [object instanceMethodSelect:@"TestMethodTwoWithBasicType:andSecond:"parameter:&par4,&par5, nil];

调用方法:- (BOOL)TestMethodTwoWithStructType:(CGRect)struOne and:(CGSize)struTwo;

//step 四二: 实例对象调用- 方法 - 传入结构体

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];

调用方法:- (NSString*)TestMethodTwoWithBlockType:(void(^)(NSString *str1))block;

//step 四三: 实例对象调用- 方法 - 传入block块

 NSObject  *object = [[TKRouter router]routerGetInstanceWithClassName:@"TKMethodTest"];

void(^parblock8)(NSString *str1) = ^(NSString *str1){

 NSLog(@"\n block 得到的值回调。==%@\n\n\n",str1);

            };

ReturnStruct returnThere = [object instanceMethodSelect:@"TestMethodTwoWithBlockType:" parameter:&parblock8, nil];

以上是基本的调用,更多的去github上download下来可自行查看。(地址:https://github.com/Tkoul/TKRouter)

比如:初始化ctrl,TKRouter给ctrl赋值,TKRouter调用push,推出新的视图,TKRouter设置代理!实现基本数据类型,结构体,oc类型,block块,代理等!

如果有帮到你,请去俺的https://github.com/Tkoul/TKRouter地址上 star一下。

欢迎大家交流,email:Tkoull@163.com 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270