iOS组件化 方案 实现

news2024/12/27 1:40:17

iOS组件化

  • 组件化的原因
  • 现在流行的组件化方案
    • 方案一、url-block (基于 URL Router)
    • 方案二、protocol
      • 调用方式解读
    • 方案三、target-action
      • 调用方式解读
  • gitHub代码链接参考

组件化的原因

  • 模块间解耦
  • 模块重用
  • 提高团队协作开发效率
  • 单元测试

当项目App处于起步阶段、各个需求模块趋于成熟稳定的过程中,组件化也许并没有那么迫切,甚至考虑组件化的架构可能会影响开发效率和需求迭代。而当项目迭代到一定时期之后,便会出现一些相对独立的业务功能模块,而团队的规模也会随着项目迭代逐渐增长,这便是中小型应用考虑组件化的时机了。

为了更好的分工协作,团队会安排团队成员各自维护一个相对独立的业务组件。这个时候我们引入组件化方案,一是为了解除组件之间相互引用的代码硬依赖,二是为了规范组件之间的通信接口; 让各个组件对外都提供一个黑盒服务,而组件工程本身可以独立开发测试,减少沟通和维护成本,提高效率。

进一步发展,当团队涉及到转型或者有了新的立项之后,一个团队会开始维护多个项目App,而多个项目App的需求模块往往存在一定的交叉,而这个时候组件化给我们的帮助会更大,我只需要将之前的多个业务组件模块在新的主App中进行组装即可快速迭代出下一个全新App。

现在流行的组件化方案

方案一、url-block (基于 URL Router)

通过在启动时(load方法中)注册组件提供的服务,把调用组件使用的url和组件提供的服务block对应起来,保存到内存中。在使用组件的服务时,通过url找到对应的block,然后通过block回调获取服务。

url-block的架构图如下:
在这里插入图片描述

代码说明

首先要在 + (void)load 中进行注册

[LYXRouter registerURLPattern:@"lyx://foo/bar" toHandler:^(NSDictionary *routerParameters) {
        // create view controller
    	// push view controllerstringWithFormat:@"routerParameters:%@", routerParameters]];
    }];

然后调用的时候传入url:

    [MGJRouter openURL:@"lyx://foo/bar"];

代码内部会通过传入的url,拿到对应的block,然后进行调用。
之后block中的回调内部 就会执行 跳转页面的代码了。

使用url-block的方案的确可以组建间的解耦,但是还是存在其它明显的问题,比如:

  • 需要在内存中维护url-block的表,组件多了可能会有内存问题
  • url的参数传递受到限制,只能传递常规的字符串参数,无法传递非常规参数,如UIImage、NSData等类型
  • 没有区分本地调用和远程调用的情况,尤其是远程调用,会因为url参数受限,导致一些功能受限
  • 组件本身依赖了中间件,且分散注册使的耦合较多

方案二、protocol

是通过protocol定义服务接口,组件通过实现该接口来提供接口定义的服务,具体实现就是把protocolclass做一个映射,同时在内存中保存一张映射表,使用的时候,就通过protocol找到对应的class来获取需要的服务。

protocol - class 架构图如下:
请添加图片描述

调用方式解读

注册:

[ModuleManager registerClass:ClassA forProtocol:ProtocolA]

调用:

[ModuleManager classForProtocol:ProtocolA]

具体流程可参考如下:
创建中间件
1、创建 组件化的中间件manager,中间件 提供注册机制的方法,通过字典存储 procotol-class
2、中间件manager 提供 通过协议获取class的方法

- (void)registServiceProvide:(id)provide forProcotol:(Protocol *)procotol;

- (id)serviceProvideForProcotol:(Protocol *)procotol;

业务侧提供协议 + 遵循协议的类
1、提供协议,协议中提供 需要的方法

@protocol ProductDetailServiceProcotol <NSObject>
- (UIViewController *)productDetailViewControllerWithProductId:(NSString *)productId;

@end

2、创建类,类遵循协议,实现协议方法,方法内部提供想要的 代码
3、创建的类中的+ (void)load方法,内部 调用 中间件 注册protocol-calss

@interface ProductDetailServiceProvide ()<ProductDetailServiceProcotol>

@end

@implementation ProductDetailServiceProvide

//load 方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法
+ (void)load
{
    [[ProcotolManager sharedManger] registServiceProvide:[[self alloc] init] forProcotol:@protocol(ProductDetailServiceProcotol)];
}

#pragma mark - ProductDetailServiceProcotol

- (UIViewController *)productDetailViewControllerWithProductId:(NSString *)productId
{
    ProcotolProductDetailViewController *detailVC = [[ProcotolProductDetailViewController alloc] init];
    detailVC.productId = productId;
    return detailVC;
}

@end

调用
通过协议找到类,然后调用协议 方法「即:最终走的是 协议找到的那个class的方法」

id<ProductOrderServiceProcotol> servicePrivide = [[ProcotolManager sharedManger] serviceProvideForProcotol:@protocol(ProductOrderServiceProcotol)];
    UIViewController *orderVC = [servicePrivide productOrderWithProductId:self.productId];
    [self.navigationController pushViewController:orderVC animated:YES];

这种方案确实解决了方案一中无法传递非常规参数的问题,使得组件间的调用更为方便,但是它依然没有解决组件依赖中间件的问题、内存中维护映射表的问题、组件的分散调用的问题。

方案三、target-action

重点词: 分类 runtime
该方案 中间件是通过runtime来调用组件的服务,是真正意义上的解耦,也是该方案最核心的地方。具体实施过程是给组件封装一层target对象来对外提供服务,不会对原来组件造成入侵;然后,通过实现中间件的category来提供服务给调用者,这样使用者只需要依赖中间件,而组件则不需要依赖中间件。

调用方式解读

创建中间件
中间件内部实现是通过runtime 拿到类和方法,进行调用的

@interface SYMediator : NSObject
+(instancetype)shareInstance;

- (id)performTargetName:(NSString *)targetName actionName:(NSString *)actionName param:(NSDictionary *)dicParam;
@end

创建中间件的分类
分类中 的方法 调用 中间件的performTarget... 方法,来实现最终的方法调用。


#import "SYMediator+BookVC.h"

static NSString *const kBookTarget = @"BookTarget";
static NSString *const kBookAction = @"bookVCWithParam";

@implementation SYMediator (BookVC)
- (UIViewController *)bookViewControllerWithDicParam:(NSDictionary *)dicParm
{
    UIViewController *vc = [self performTargetName:kBookTarget actionName:kBookAction param:dicParm];
    if ([vc isKindOfClass:[UIViewController class]]) {
        return vc;
    } else {
        return [[UIViewController alloc] init];
    }
}
@end


创建target

组件封装一层target对象来对外提供服务

@implementation BookTarget
- (UIViewController *)bookVCWithParam:(NSDictionary *)dicParm
{
    BookViewController *bookVC = [[BookViewController alloc] init];
    bookVC.bookName = dicParm[@"bookName"];
    bookVC.bookId = dicParm[@"bookid"];
    return bookVC;
}
@end

调用

NSDictionary *dicParm = @{@"bookName" : @"降龙十八掌",@"bookid" : @"sy0001"};
    //第一种方式(有category)
    UIViewController *bookVC = [[SYMediator shareInstance] bookViewControllerWithDicParam:dicParm];
    [self.navigationController pushViewController:bookVC animated:YES];

gitHub代码链接参考

https://github.com/liyuunxiangGit/iOS-modularization

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1718509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

例子:Triton + TensorRT-LLM

Deploy an AI Coding Assistant with NVIDIA TensorRT-LLM and NVIDIA Triton | NVIDIA Technical Blog https://github.com/triton-inference-server/tutorials/blob/main/Conceptual_Guide/Part_1-model_deployment/README.md 1. 想用onnx-runtime来做推理backend&#xff1…

React + Taro 项目 实际书写 感受

之前我总结了部分react 基础 根据官网的内容 以及Taro 框架的内容 今天我试着开始写了一下页面和开发 说一下我的感受 我之前写的是vue3 今天是第一次真正根据需求做页面开发 和逻辑功能 代码的书写 主体就是开发了这个页面 虽说这个页面 很简单 但是如果你要是第一次写 难说…

Facebook的算法揭秘:如何塑造我们的信息

在当今数字化时代&#xff0c;Facebook已经成为人们日常生活中不可或缺的一部分。其信息流算法不仅决定着我们在平台上看到的内容&#xff0c;还对我们的观点、行为和体验产生了深远的影响。本文将深入探讨Facebook的算法运作方式&#xff0c;以及它对我们信息获取和社交行为的…

神器!!Python热重载调试【送源码】

在 Python 开发的路上&#xff0c;调试是我们不可避免的一环。 而今天推荐的开源项目Reloadium &#xff0c;让你在不重启程序的情况下实现代码的即时更新和调试。 &#x1f504; Reloadium 功能亮点&#xff1a; 1. 热重载魔法&#xff1a; Reloadium 不仅仅能够实现代码的…

Android高通 12/13 录屏流程代码位置

需求如下图 实现系统录屏功能 frameworks/base/packages/SystemUI/src/com/android/systemui/screenrecord 涉及代码 ScreenRecordDialog # startBtn RecordingService # startRecording# stopRecording ScreenMediaRecorder # start # end #save 1、点击开始录屏framewo…

停车场车位引导系统方案升级实施步骤流程是什么,有什么注意事项

停车场车位引导系统是一种现代化的停车管理系统&#xff0c;它通过实时监测车位占用情况&#xff0c;并向驾驶员提供准确的空闲车位导航信息&#xff0c;从而提高停车场的使用效率和用户体验。随着城市交通的快速发展和车辆数量的不断增加&#xff0c;停车场车位引导系统已成为…

【数据分享】中国科技统计年鉴Excel版(1991-2023年)

大家好&#xff01;今天我要向大家介绍一份重要的中国科技统计数据资源——《中国科技统计年鉴》。这份年鉴涵盖了从1991年到2023年中国科技统计全面数据&#xff0c;并提供限时免费下载。 数据介绍 在数字化时代的浪潮中&#xff0c;数据的重要性日益凸显。对于研究人员、政…

AutoSQT 2024汽车软件质量与测试峰会开启注册 | 智能汽车软件如何卷出差异化?

在汽车行业向智能化、网联化转型的大趋势下&#xff0c;软件在汽车系统中扮演着越来越核心的角色。基于“软件定义汽车”的行业共识&#xff0c;各主机厂正在不断押注软件开发&#xff0c;以实现品牌差异化竞争。 例如&#xff0c;大众集团正在开发下一代汽车操作系统和应用软…

Spring MVC 应⽤分层

什么是应用分层 引用分层是一种软件开发思想 将应用程序分为N个层次每个层次负责各个职责 其中MVC是常见的设计模式这就是应用分层的具体体现 目前主流的开发方式是前后段分离后端开发工程师不再需要关注前端的实现,对此就需要分为表现层&#xff0c;数据层&#xff0c;业务逻…

LM2733升压芯片

具有 40V 内部 FET 开关且采用 SOT-23 封装的 LM2733 0.6MHz 和 1.6MHz 升压转换器 外观 参考价格 1 特性 电路原理图 基于LM2733升压电路设计-CSDN博客https://blog.csdn.net/qq_31251431/article/details/107479885 特此记录 anlog 2024年5月31日 高压方案 此方案经过更多…

数据结构 | 二叉树(基本概念、性质、遍历、C代码实现)

1.树的基本概念 树是一种 非线性 的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#xff0c;称为根…

ChatGPT的逆袭历程:核心技术深度解析

在ChatGPT问世之前&#xff0c;已有许多大模型存在&#xff0c;但为何只有它成为了AI时代的“iPhone时刻”&#xff1f;这不仅得益于其技术优势&#xff0c;还在于其发展过程中所采用的一系列创新策略。本文将深度复盘ChatGPT的逆袭历程&#xff0c;分析其核心技术&#xff0c;…

GIS毕业薪资从2K到20K究竟要多久?

同大多数行业一样&#xff0c;GIS毕业生薪资跟行业有密切关系。 测绘地理信息行业紧跟时代步伐&#xff0c;随着测绘地理信息技术的变革和进步&#xff0c;测绘产品也逐渐升级发展。 经过三个阶段的发展&#xff0c;测绘地理信息产品初步实现从抽象到真实、从平面到立体、从静…

npm run dev 同时运行vue前端项目和node后端项目

将两个项目放到一个目录下 项目拖进vscode中&#xff0c;安装包依赖&#xff0c;修改配置 npm i concurrently "dev": "concurrently \"vite --mode development\" \"nodemon app.js\"" 命令行 npm run dev 运行 没有运行成功排查 …

window11 设置 ubuntu2204 至最佳体验(安装/右键菜单/root用户/docker)

前言 在 window 中如果不使用 ubuntu 命令行会非常不方便&#xff0c;还好微软提供了 ubuntu 的终端&#xff0c;下载安装后简单设置下就可以愉快的使用了。 本文会涉及的方面 安装右键菜单设置root 用户设置docker 设置 安装 ubuntu 到微软的软件商店中下载安装即可&…

探索python数据可视化的奥秘:打造专业绘图环境

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、搭建专业绘图环境 二、掌握绘图基本原理 三、解锁绘图高级技巧 四、总结与展望 在数据…

taskENTER_CRITICAL()分析

1. 临界段代码 //任务级的临界段代码保护 taskENTER_CRITICAL() taskEXIT_CRITICAL()//中断级的临界段代码保护 taskENTER_CRITICAL_FROM_ISR() taskEXIT_CRITICAL_FROM_ISR()2. 以STM32为例 &#xff08;1&#xff09;STM32有0~15&#xff0c;共16级中断&#xff0c;可嵌套…

【linux】开机调用python脚本

linux中&#xff0c;可以使用crontab 设置开机自动调用 crontab的安装在前面文章里写过了&#xff0c;不再重复 首先&#xff0c;还是进入crontab配置文件 crontab -e 进入之后&#xff0c;跟其他定时任务不同&#xff0c;只需要在时间配置那里用rebooot 这类之后的两个文件的…

计算机图形学入门05:投影变换

1.投影变换 上一章已经介绍了投影变换&#xff0c;就是将三维图像投影到二维平面上&#xff0c;而投影变换又分为正交投影(Orthographic Projection)和透视投影(Perspective Projection)。如下图&#xff1a; 正交投影 没有近大远小的现象&#xff0c;无论图形与视点距离是远是…

Three.js 研究:4、创建设备底部旋转的科技感圆环

1、实现效果 2、PNG转SVG 2.1、原始物料 使用网站工具https://convertio.co/zh/png-svg/进行PNG转SVG 3、导入SVG至Blender 4、制作旋转动画 4.1、给圆环着色 4.2、修改圆环中心位置 4.3、让圆环旋转起来 参考一下文章 Three.js 研究&#xff1a;1、如何让物体动起来 Thre…