利用runtime来给组件化项目appdelegate减负

前言

本文主要依赖我写的两个工具

1.UCRuntimeKit:这个小工具主要是为了能够利用字符串+runtime动态的调用方法.经过了500多条单元测试,基本满足所有的使用场景,安全,且支持向调用方抛出error,但不会crash.在这里它主要是为了向各个组件中的delegate转发多参数方法用的.

2.UCAppDelegateReduce.这个小工具依赖上面的UCRuntimeKit来做消息转发.

实现原理

  • 1.先将项目中的delegate与框架中的UCAppDelegateRealize实现的22个方法进行交换,如果appdelegate没实现这个方法则不会交换,交换完成后不影响之前的逻辑,依旧会先调用原先appdelegate的逻辑,如果这22个方法没有包含你需要转发给组件的方法的话支持扩展.

  • 2.当delegate接收到调用时,会自动来到UCAppDelegateRealize,这里在会根据位移枚举的配置来对各个组件调用,这个调用过程依赖UCRuntimeKit,十分安全,不会crash.

使用

可以利用cocoapod进行导入,pod 'UCAppDelegateReduce'

Objc中的使用

ObjcDemo

  • 1.新建一个Objc类,例如我这里取名叫AppDelegateExchange

  • 2.在load类方法里进行下面的配置,就可以了

      + (void)load {
    
      UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share];
      // sendMessageType 是位移枚举,可以选择自己想给子模块派发的方法
      UCAppDelegateConfigModel *model1 = [[UCAppDelegateConfigModel alloc] initWithModuleName:@"UCObjcModule1AppDelegate" sendMessageType:didFinishLaunchingWithOptions];
      UCAppDelegateConfigModel *model2 = [[UCAppDelegateConfigModel alloc] initWithModuleName:@"UCObjcModule2AppDelegate" sendMessageType:handleOpenURL | didFinishLaunchingWithOptions];
      
      [manager startExchangeMethodWithOriginalAppDelegateName:@"UCAppDelegate" newModuleAppDelegateConfigArray:@[model1, model2]];
      }
    

Swift的使用

SwiftDemo

  • 1.新建一个Objc类,例如我这里取名叫AppDelegateExchange

  • 2.要转发的Module中的appdelegate方法前要加@objc,否则不支持动态调用

  • 3.在load类方法里进行下面的配置,就可以了

      + (void)load {
      
      UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share];
      
      // 这里Objc调用Swift需要加上类似命名空间的前缀,否则找不到这个Swift class
      NSString *swiftModule1Name = [UCMediatorParameterParser getObjcClassName:@"SwiftModule1AppDelegate"];
      // 支持位移枚举
      UCAppDelegateConfigModel *model1 = [[UCAppDelegateConfigModel alloc] initWithModuleName:swiftModule1Name sendMessageType:didFinishLaunchingWithOptions];
      
      NSString *swiftModule2Name = [UCMediatorParameterParser getObjcClassName:@"SwiftModule2AppDelegate"];
      UCAppDelegateConfigModel *model2 = [[UCAppDelegateConfigModel alloc] initWithModuleName:swiftModule2Name sendMessageType:handleOpenURL | didFinishLaunchingWithOptions];
      
      NSString *originalDelegateName = [UCMediatorParameterParser getObjcClassName:@"AppDelegate"];
      [manager startExchangeMethodWithOriginalAppDelegateName:originalDelegateName newModuleAppDelegateConfigArray:@[model1, model2]];
      }
    

UCAppDelegateConfigModel是很灵活的,支持位移枚举配置,配置后不会调用未配置的方法,另外manager的配置在app的生命周期中只应该在最开始load的时候配置一次!配置完成后这里会解析,生成类似这样的map,以代理方法名为key,需要转发的类名集合为value,并将这个map缓存在内存中,方便快速转发给各个组件.

这样你就可以把例如原先写在appdelegate中的开屏配置,分享key配置,支付配置,push路由配置,3Dtouch等等直接写在各自的模块中了,这里的调用顺序也是可以通过配置来决定的.

但是如果这个调用是异步的,例如组件B的一个功能依赖组件B的回调,建议还是把这个写在组件a的delegate实现里.

做完了这些你会发现你原来的delegate基本可以什么都不写了,他已经把业务分散到各个组件中去了.

UT

关于单元测试,这里基本只是测试了调用这个模块的,转发各个模块都是手动测得,判断参数能传入到各个组件就没有更深度的写了,这里的单元测试确实不太好写.

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、你在项目中用过 runtime 吗?举个例子。 a、Method Swizzling动态交换方法实现,实则交换...
    写代码的小农民阅读 1,394评论 0 4
  • iOS网络架构讨论梳理整理中。。。 其实如果没有APIManager这一层是没法使用delegate的,毕竟多个单...
    yhtang阅读 5,252评论 1 23
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,776评论 0 9
  • 最近一朋友正准备跳槽,就从各处搜索整理一些基础,便于朋友复习,也便于自己复习查看. 1. 回答person的ret...
    smile丽语阅读 1,802评论 0 7
  • 1.最喜欢看可可睡觉的样子,安安静静,一呼一吸。我随意地亲吻她,软软肉肉的脸蛋,真可爱。每天都看不腻,亲不腻。 2...
    春娟Jane阅读 141评论 0 1