收款定制开发iOS 组件化的三种方案

组件化

收款定制开发本文主要介绍iOS收款定制开发组件化收款定制开发的三种方案


1、常⽤的三种方案

  • URL Scheme
  • Target - Action
  • Protocol - Class 匹配

1.1、 URL 路由

  • 使 URL 收款定制开发处理本地的跳转
  • 收款定制开发通过中间层进⾏注册 & 调⽤ (load收款定制开发方法里把被调用者注册到中间层)
  • 注册表⽆收款定制开发需使用反射
  • 非懒加载 / 收款定制开发注册表的维护 / 参数

URL Scheme路由示例 

  1. //MTMediator.h --- start
  2. typedef void(^MTMediatorProcessBlock)(NSDictionary *params);
  3. + (void)registerScheme:(NSString *)scheme processBlock:(MTMediatorProcessBlock)processBlock;
  4. + (void)openUrl:(NSString *)url params:(NSDictionary *)params;
  5. //MTMediator.h --- end
  6. //MTMediator.m --- start
  7. + (NSMutableDictionary *)mediatorCache{
  8. static NSMutableDictionary *cacheScheme;
  9. static dispatch_once_t onceToken;
  10. dispatch_once(&onceToken, ^{
  11. cacheScheme = @{}.mutableCopy;
  12. });
  13. return cacheScheme;
  14. }
  15. + (void)registerScheme:(NSString *)scheme processBlock:(MTMediatorProcessBlock)processBlock{
  16. if (scheme.length > 0 && processBlock) {
  17. [[[self class] mediatorCache] setObject:processBlock forKey:scheme];
  18. }
  19. }
  20. + (void)openUrl:(NSString *)url params:(NSDictionary *)params{
  21. MTMediatorProcessBlock block = [[[self class] mediatorCache] objectForKey:url];
  22. if (block) {
  23. block(params);
  24. }
  25. }
  26. //MTMediator.m --- end
  27. //注册 --- start
  28. + (void)load {
  29. [MTMediator registerScheme:@"detail://" processBlock:^(NSDictionary * _Nonnull params) {
  30. NSString *url = (NSString *)[params objectForKey:@"url"];
  31. UINavigationController *navigationController = (UINavigationController *)[params objectForKey:@"controller"];
  32. MTDetailViewController *controller = [[MTDetailViewController alloc] initWithUrlString:url];
  33. // controller.title = [NSString stringWithFormat:@"%@", @(indexPath.row)];
  34. [navigationController pushViewController:controller animated:YES];
  35. }];
  36. }
  37. //注册 --- end
  38. //调用 --- start
  39. //URL Scheme
  40. [MTMediator openUrl:@"detail://" params:@{@"url":item.articleUrl,@"controller":self.navigationController}];
  41. //调用 --- end
  42. 复制代码
  • 收款定制开发参考了系统URL Scheme机制
  • 收款定制开发参数传递通过dictionary,收款定制开发对调用者不透明

目前iOS收款定制开发上大部分路由工具都是基于URL 进行匹配的,或者命名约定,通过runtime方法进行动态调用

优点:实现简单

缺点:需要维护字符串表,依赖于命名约定,无法在编译时暴露出所有问题,需要在运行时才能发现错误。

MGJRouter

URL路由方式主要是以蘑菇街为代表的的

实现原理:

  • App启动时实例化各组件模块,然后这些组件向ModuleManager注册Url,有些时候不需要实例化,使用class注册
  • 当组件A需要调用组件B时,向ModuleManager传递URL,参数跟随URL以GET方式传递,类似openURL。然后由ModuleManager负责调度组件B,最后完成任务。
  1. // 1、注册某个URL
  2. MGJRouter.registerURLPattern("app://home") { (info) in
  3. print("info: (info)")
  4. }
  5. //2、调用路由
  6. MGJRouter.openURL("app://home")
  7. 复制代码

URL 路由的优点

  • 极高的动态性,适合经常开展运营活动的app
  • 方便地统一管理多平台的路由规则
  • 易于适配URL Scheme,可以下发

URl 路由的缺点

  • 传参方式有限,并且无法利用编译器进行参数类型检查,因此所有的参数都是通过字符串转换而来
  • 只适用于界面模块,不适用于通用模块
  • 参数的格式不明确,是个灵活的 dictionary,也需要有个地方可以查参数格式。
  • 不支持storyboard
  • 依赖于字符串硬编码,难以管理,蘑菇街做了个后台专门管理。
  • 无法保证所使用的的模块一定存在
  • 解耦能力有限,url 的”注册”、”实现”、”使用”必须用相同的字符规则,一旦任何一方做出修改都会导致其他方的代码失效,并且重构难度大

1.2、Target - Action

  • 抽离业务逻辑
  • 通过中间层进行调⽤
  • 中间层使⽤ runtime 反射
  • 中间层代码优化

Target - Action示例 

  1. //MTMediator.h
  2. #import <UIKit/UIKit.h>
  3. #import <Foundation/Foundation.h>
  4. NS_ASSUME_NONNULL_BEGIN
  5. @interface MTMediator : NSObject
  6. //target action
  7. + ( __kindof UIViewController *)detailViewControllerWithUrl:(NSString *)detailUrl;
  8. @end
  9. NS_ASSUME_NONNULL_END
  10. //MTMediator.m
  11. #import "MTMediator.h"
  12. @implementation MTMediator
  13. + ( __kindof UIViewController *)detailViewControllerWithUrl:(NSString *)detailUrl{
  14. Class detailVC = NSClassFromString(@"MTDetailViewController");
  15. UIViewController *controller = [[detailVC alloc] performSelector:NSSelectorFromString(@"initWithUrlString:") withObject:detailUrl];
  16. return controller;
  17. }
  18. @end
  19. //调用
  20. //Target - Action
  21. UIViewController *vc = [MTMediator detailViewControllerWithUrl:item.articleUrl];
  22. vc.title = @"详情啊";
  23. [self.navigationController pushViewController:vc animated:YES];
  24. 复制代码
  • 硬编码方式(直接调用,不利于维护和扩展)
  • perform 最多能传递2个参数,可以传入字典避免参数过多
  • initWithUrlString:方法必须实现 否则找不到sel崩溃
  • 业务逻辑柔合在Mediator中,可以各个模块写各自的MTMediator扩展

CTMediator

原理是通过oc的runtime、category特性动态获取模块,例如通过NSClassFromString获取类并创建实例,通过performSelector + NSInvocation动态调用方法。

实现原理:

  • 1、利用分类为路由添加新接口,在接口中通过字符串获取对应的类
  • 2、通过runtime创建实例,动态调用实例的方法

CTMediator使用

  1. //******* 1、分类定义新接口
  2. extension CTMediator{
  3. @objc func A_showHome()->UIViewController?{
  4. //在swift中使用时,需要传入对应项目的target名称,否则会找不到视图控制器
  5. let params = [
  6. kCTMediatorParamsKeySwiftTargetModuleName: "CJLBase_Example"
  7. ]
  8. //CTMediator提供的performTarget:action:params:shouldCacheTarget:方法 通过传入name,找到对应的targer和action
  9. if let vc = self.performTarget("A", action: "Extension_HomeViewController", params: params, shouldCacheTarget: false) as? UIViewController{
  10. return vc
  11. }
  12. return nil
  13. }
  14. }
  15. //******* 2、模块提供者提供target-action的调用方式(对外需要加上public关键字)
  16. class Target_A: NSObject {
  17. @objc func Action_Extension_HomeViewController(_ params: [String: Any])->UIViewController{
  18. let home = HomeViewController()
  19. return home
  20. }
  21. }
  22. //******* 3、使用
  23. if let vc = CTMediator.sharedInstance().A_showHome() {
  24. self.navigationController?.pushViewController(vc, animated: true)
  25. }
  26. 复制代码

模块间的关系:

模块A——Mediator——target——模块B

优点

  • 1、利用接口调用,实现了参数传递时的类型安全
  • 2、直接使用模块的protocol接口,无需再重复封装

缺点

  • 1、用框架来创建所有对象,创建方式不同,即不支持外部传入参数
  • 2、用OC runtime创建对象,不支持swift
  • 3、只做了protocol 和 class 的匹配,不支持更复杂的创建方式 和依赖注入
  • 4、无法保证所使用的protocol 一定存在对应的模块,也无法直接判断某个protocol是否能用于获取模块

1.2、Protocol - Class

  • 增加 Protocol Wrapper层 (中间件先注册Protocol和Class对应关系,将protocol和对应的进行字典匹配
  • 中间件返回 Protocol 对应的 Class,然后动态创建实例
  • 解决硬编码的问题

Protocol - Class示例

  1. //具体的Protocol
  2. //MTMediator.h --- start
  3. @protocol MTDetailViewControllerProtocol <NSObject>
  4. + (__kindof UIViewController *)detailViewControllerWithUrl:(NSString *)detailUrl;
  5. @end
  6. @interface MTMediator : NSObject
  7. + (void)registerProtol:(Protocol *)protocol class:(Class)cls;
  8. + (Class)classForProtocol:(Protocol *)protocol;
  9. @end
  10. //MTMediator.h --- end
  11. //MTMediator.m --- start
  12. + (void)registerProtol:(Protocol *)protocol class:(Class)cls{
  13. if (protocol && cls) {
  14. [[[self class] mediatorCache] setObject:cls forKey:NSStringFromProtocol(protocol)];
  15. }
  16. }
  17. + (Class)classForProtocol:(Protocol *)protocol{
  18. return [[[self class] mediatorCache] objectForKey:NSStringFromProtocol(protocol)];
  19. }
  20. //MTMediator.m --- end
  21. //被调用
  22. //MTDetailViewController.h --- start
  23. @protocol MTDetailViewControllerProtocol;
  24. @interface MTDetailViewController : UIViewController<MTDetailViewControllerProtocol>
  25. @end
  26. //MTDetailViewController.h --- end
  27. //MTDetailViewController.m --- start
  28. + (void)load {
  29. [MTMediator registerProtol: @protocol(MTDetailViewControllerProtocol) class:[self class]];
  30. }
  31. #pragma mark - MTDetailViewControllerProtocol
  32. + ( __kindof UIViewController *)detailViewControllerWithUrl:(NSString *)detailUrl{
  33. return [[MTDetailViewController alloc]initWithUrlString:detailUrl];
  34. }
  35. //MTDetailViewController.m --- end
  36. //调用
  37. Class cls = [MTMediator classForProtocol: @protocol(MTDetailViewControllerProtocol)];
  38. if ([cls respondsToSelector: @selector(detailViewControllerWithUrl:)]) {
  39. [self.navigationController pushViewController:[cls detailViewControllerWithUrl:item.articleUrl] animated:YES];
  40. }
  41. 复制代码
  • 被调用者先在中间件注册Protocol和Class对应关系,对外只暴漏Protocol

BeeHive

protocol比较典型的三方就是。BeeHive借鉴了Spring Service、Apache DSO的架构理念,采用AOP+扩展App生命周期API形式,将业务功能基础功能模块以模块方式以解决大型应用中的复杂问题,并让模块之间以Service形式调用,将复杂问题切分,以AOP方式模块化服务。

BeeHive 核心思想

  • 1、各个模块间调用从直接调用对应模块,变成调用Service的形式,避免了直接依赖。
  • 2、App生命周期的分发,将耦合在AppDelegate中逻辑拆分,每个模块以微应用的形式独立存在。

示例如下:

  1. //******** 1、注册
  2. [[BeeHive shareInstance] registerService:@protocol(HomeServiceProtocol) service:[BHViewController class]];
  3. //******** 2、使用
  4. #import "BHService.h"
  5. id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
  6. 复制代码

优点

  • 1、利用接口调用,实现了参数传递时的类型安全
  • 2、直接使用模块的protocol接口,无需再重复封装

缺点

  • 1、用框架来创建所有对象,创建方式不同,即不支持外部传入参数
  • 2、用OC runtime创建对象,不支持swift
  • 3、只做了protocol 和 class 的匹配,不支持更复杂的创建方式 和依赖注入
  • 4、无法保证所使用的protocol 一定存在对应的模块,也无法直接判断某个protocol是否能用于获取模块

建议:URL Scheme - handler 配合 Protocol - Class 使用
 

附带:iOS组件化方案架构设计图


​​​​​​​

 

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发