我的编程空间,编程开发者的网络收藏夹
学习永远不晚

iOS 组件化的三种方案

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

iOS 组件化的三种方案

组件化

本文主要介绍iOS组件化的三种方案


1、常⽤的三种方案

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

1.1、 URL Scheme路由

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

URL Scheme路由示例 

//MTMediator.h --- starttypedef void(^MTMediatorProcessBlock)(NSDictionary *params);+ (void)registerScheme:(NSString *)scheme processBlock:(MTMediatorProcessBlock)processBlock;+ (void)openUrl:(NSString *)url params:(NSDictionary *)params;//MTMediator.h --- end//MTMediator.m --- start+ (NSMutableDictionary *)mediatorCache{    static NSMutableDictionary *cacheScheme;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        cacheScheme = @{}.mutableCopy;    });    return cacheScheme;}+ (void)registerScheme:(NSString *)scheme processBlock:(MTMediatorProcessBlock)processBlock{    if (scheme.length > 0 && processBlock) {        [[[self class] mediatorCache] setObject:processBlock forKey:scheme];    }}+ (void)openUrl:(NSString *)url params:(NSDictionary *)params{    MTMediatorProcessBlock block = [[[self class] mediatorCache] objectForKey:url];    if (block) {        block(params);    }}//MTMediator.m --- end//注册 --- start+ (void)load {    [MTMediator registerScheme:@"detail://" processBlock:^(NSDictionary * _Nonnull params) {        NSString *url = (NSString *)[params objectForKey:@"url"];        UINavigationController *navigationController = (UINavigationController *)[params objectForKey:@"controller"];        MTDetailViewController *controller = [[MTDetailViewController alloc] initWithUrlString:url];//        controller.title = [NSString stringWithFormat:@"%@", @(indexPath.row)];        [navigationController pushViewController:controller animated:YES];    }];}//注册 --- end//调用 --- start//URL Scheme[MTMediator openUrl:@"detail://" params:@{@"url":item.articleUrl,@"controller":self.navigationController}];//调用 --- end复制代码
  • 参考了系统URL Scheme机制
  • 参数传递通过dictionary,对调用者不透明

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

优点:实现简单

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

MGJRouter

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

实现原理:

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

URL 路由的优点

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

URl 路由的缺点

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

1.2、Target - Action

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

Target - Action示例 

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

CTMediator

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

实现原理:

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

CTMediator使用

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

模块间的关系:

模块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示例

//具体的Protocol//MTMediator.h --- start@protocol MTDetailViewControllerProtocol + (__kindof UIViewController *)detailViewControllerWithUrl:(NSString *)detailUrl;@end@interface MTMediator : NSObject+ (void)registerProtol:(Protocol *)protocol class:(Class)cls;+ (Class)classForProtocol:(Protocol *)protocol;@end//MTMediator.h --- end//MTMediator.m --- start+ (void)registerProtol:(Protocol *)protocol class:(Class)cls{    if (protocol && cls) {        [[[self class] mediatorCache] setObject:cls forKey:NSStringFromProtocol(protocol)];    }}+ (Class)classForProtocol:(Protocol *)protocol{    return [[[self class] mediatorCache] objectForKey:NSStringFromProtocol(protocol)];}//MTMediator.m --- end//被调用//MTDetailViewController.h --- start@protocol MTDetailViewControllerProtocol;@interface MTDetailViewController : UIViewController@end//MTDetailViewController.h --- end//MTDetailViewController.m --- start+ (void)load {    [MTMediator registerProtol: @protocol(MTDetailViewControllerProtocol) class:[self class]];}#pragma mark - MTDetailViewControllerProtocol+ ( __kindof UIViewController *)detailViewControllerWithUrl:(NSString *)detailUrl{    return [[MTDetailViewController alloc]initWithUrlString:detailUrl];}//MTDetailViewController.m --- end//调用Class cls = [MTMediator classForProtocol: @protocol(MTDetailViewControllerProtocol)];if ([cls respondsToSelector: @selector(detailViewControllerWithUrl:)]) {        [self.navigationController pushViewController:[cls detailViewControllerWithUrl:item.articleUrl] animated:YES];}复制代码
  • 被调用者先在中间件注册Protocol和Class对应关系,对外只暴漏Protocol

BeeHive

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

BeeHive 核心思想

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

示例如下:

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

优点

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

缺点

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

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

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


​​​​​​​

 

来源地址:https://blog.csdn.net/yezuiqingxin/article/details/126018623

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

iOS 组件化的三种方案

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

数组的三种初始化方式

1. 直接初始化:在声明数组的同时给出初始值,例如:`int[] arr = {1, 2, 3, 4, 5};` 这种方式适用于已知数组元素的情况。2. 动态初始化:先声明数组,然后通过`new`关键字为数组分配内存空间,并给出初始值。例如
2023-09-01

ios组件化开发的方法是什么

iOS组件化开发的方法有很多种,以下是其中几种常用的方法:1. CocoaPods:使用CocoaPods可以方便地管理项目中的各个组件。每个组件都会以Pod的形式进行管理,并通过Podfile文件来指定项目所需要的组件。可以通过私有Pod
2023-08-15

详解iOS设置字体的三种方式

有时候项目需要显示一些非系统的字体达到一些UI的效果,目前设置字体有三种方式,默认方式、bundle方式,coreText方式。 1 默认方式 这种方式就是正常的字体设置方式label.font = [UIFont fontwithname
2022-05-22

Vue父子组件传值的三种方法

这篇文章主要介绍了Vue父子组件传值的三种方法,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-12-20

Node.js编写组件的三种实现方式

首先介绍使用v8 API跟使用swig框架的不同: (1)v8 API方式为官方提供的原生方法,功能强大而完善,缺点是需要熟悉v8 API,编写起来比较麻烦,是js强相关的,不容易支持其它脚本语言。 (2)swig为第三方支持,一个强大的组
2022-06-04

Vue组件通信传递数据的三种方式

这篇文章主要介绍了Vue组件通信传递数据的三种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-05-17

java声明数组的三种方式

Java声明数组的三种方式有:1. 静态声明:使用静态初始化方式声明数组,即在声明数组的同时,给数组元素赋初值。例如:int[] array = {1, 2, 3, 4, 5};2. 动态声明:使用动态初始化方式声明数组,即在声明数组时,只
2023-08-28

三种Node.js写文件的方式

本文分享了Node.js写文件的三种方式,具体内容和如下 1、通过管道流写文件采用管道传输二进制流,可以实现自动管理流,可写流不必当心可读流流的过快而崩溃,适合大小文件传输(推荐)var readStream = fs.createRead
2022-06-04

详解IOS判断当前网络状态的三种方法

在项目中,为了好的用户体验,有些场景必须线判断网络状态,然后才能决定该干嘛。比如视频播放,需要线判断是Wifi还是4G,Wifi直接播放,4G先提示用户。获取网络状态的方法大概有三种: 1. Reachability 这是苹果的官方演示de
2022-05-21

Python代码部署的三种加密方案

本文主要介绍了Python代码部署的三种加密方案,主要介绍了代码混淆、代码编译、代码打包这三种,具有一定的参考价值,感兴趣的可以了解一下
2023-02-06

sql跨表查询的三种方案总结

目录前言方案一:连接多个库,同步执行查询优点缺点代码执行方案二:在主数据库增加冗余表,通过定时更新cLdNwV,造成同库联表查询优点缺点相似实现场景方案三:dbLink本地连接多个库,在本地进行数据分析优点缺点前言最近又个朋友问我,如何进
2022-08-11

一文掌握Redis的三种集群方案

在开发测试环境中,我们一般搭建Redis的单实例来应对开发测试需求,但是在生产环境,如果对可用性、可靠性要求较高,则需要引入Redis的集群方案。虽然现在各大云平台有提供缓存服务可以直接使用,但了解一下其背后的实现与原理总还是有些必要(比如面试), 本文就一起
一文掌握Redis的三种集群方案
2021-08-29

编程热搜

目录