iOS组件化 方案 实现

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024最新群智能优化算法:大甘蔗鼠算法(Greater Cane Rat Algorithm,GCRA)求解23个函数,提供MATLAB代码

一、大甘蔗鼠算法 大甘蔗鼠算法&#xff08;Greater Cane Rat Algorithm&#xff0c;GCRA&#xff09;由Jeffrey O. Agushaka等人于2024年提出&#xff0c;该算法模拟大甘蔗鼠的智能觅食行为。 参考文献 [1]Agushaka J O, Ezugwu A E, Saha A K, et al. Greater Cane Rat Alg…

LAMMPS - 分子动力学模拟器

本文翻译自&#xff1a;https://www.lammps.org/ 文章目录 一、关于 LAMMPS下载作者R&D 100 二、LAMMPS 亮点毛细血管中的血流 一、关于 LAMMPS 官网&#xff1a; https://www.lammps.org/ github &#xff1a;https://github.com/lammps/lammps LAMMPS 分子动力学模拟器…

初识java——javaSE(8)异常

文章目录 一 异常的概念与体系结构1.1 什么是异常&#xff1f;1.2 异常的体系结构&#xff01;1.3 编译时异常与运行时异常与Error编译时异常&#xff1a;异常声明&#xff1a;throws关键字 运行时异常&#xff1a;什么是Error? 二 处理异常2.1 异常的抛出&#xff1a;throw(注…

利用映射算子打印菱形

文章目录 一、利用RDD完成&#xff08;一&#xff09;右半菱形&#xff08;二&#xff09;左半菱形&#xff08;三&#xff09;完整菱形&#xff08;四&#xff09;输出任意大菱形 二、利用Java完成&#xff08;一&#xff09;右半菱形&#xff08;二&#xff09;左半菱形&…

恒压频比开环控制系统Matlab/Simulink仿真分析(SPWM控制方式)

介绍恒压频比的开环控制方法驱动永磁同步电机的转动&#xff0c;首先分析恒压频比的控制原理&#xff0c;然后在Matlab/Simulink中进行永磁同步电机恒压频比开环控制系统的仿真分析&#xff0c;最后将Simulink中的恒压频比控制算法生成代码加载到实际工程中进行工程实现。 一、…

react 表格实现拖拽功能

项目背景 : react ant 单纯实现拖拽确实不难 , 我的需求是根据后台接口返回 , 生成对应的父子表格 , 并只可以拖拽子的位置 , 如图 后台返回的数据结构 (pid为0说明是父 , 子的pid等于父的id , 说明是父的子) 1 , 我先转成了树形结构且自己加上了key (注意 : key一定得是唯一的…

异常(Exception)

捕获异常 public class test {public static void main(String [] args) {int[] arr {1,2,3,4,5};try {System.out.println(arr[10]);}catch (ArrayIndexOutOfBoundsException e) {//索引越界异常System.out.println("索引越界");}System.out.println("看看我是…

测试FaceRecognitionDotNet报错“Error deserializing object of type int”

FaceRecognitionDotNet宣称是最简单的.net人脸识别模块&#xff0c;其内部使用Dlib、DlibDotNet、OpenCVSharp等模块实现人脸识别&#xff0c;网上有不少介绍文章。实际测试过程中&#xff0c;在调用FaceRecognition.Create函数创建FaceRecognition实例对象时&#xff0c;会报如…

AI入门:普通人可以利用AI做什么?休闲时间赚点小钱?(含多种实践案例)

大家好&#xff0c;我是影子&#xff0c;一名AI编程深耕者。 最近&#xff0c;有很多 AI 小白问我&#xff0c;AI到底可以做些什么&#xff1f;对我们普通人能有哪些帮助&#xff1f; 在我看来&#xff0c;对于我们刚接触 AI 的小伙伴而言。我们可以利用 AI 为我们工作提效&…

构建 VPC 并启动 Web 服务器

实验 2&#xff1a;构建 VPC 并启动 Web 服务器 目标 完成本实验后&#xff0c;您可以&#xff1a; 创建 VPC。创建子网。配置安全组。在 VPC 中启动 EC2 实例。任务 1&#xff1a;创建 VPC 在本任务中&#xff0c;您将使用 VPC 向导在单个可用区中创建一个 VPC、一个互联网网关…

神经网络---卷积神经网络CNN

一、从前馈神经网络到CNN 前馈神经网络&#xff08;Feedforward Neural Networks&#xff09;是最基础的神经网络模型&#xff0c;也被称为多层感知机&#xff08;MLP&#xff09;。 它由多个神经元组成&#xff0c;每个神经元与前一层的所有神经元相连&#xff0c;形成一个“…

电子电气SCI期刊,中科院1区TOP,收稿范围广泛

一、期刊名称 IEEE Transactions on Smart Grid 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;工程技术 影响因子&#xff1a;9.6 中科院分区&#xff1a;1区 三、期刊征稿范围 IEEE Transactions on Smart Grid是一本跨学科期刊&#xff0c;旨在传播智…

Gbase 国产数据库

参考&#xff1a;参考&#xff1a; 5分钟学会Linux环境GBase 8t安装和部署 - 光洋山 - twt企业IT交流平台 (talkwithtrend.com)https://www.talkwithtrend.com/Article/197237 视频 GBase 8s快速入门-功能简介与演示-大数据教程-腾讯课堂 (qq.com)https://ke.qq.com/course/…

Qt 插件机制使用及原理

目录 1.引言 2.插件原理 3.插件实现 3.1.定义一个接口集(只有纯虚函数的类) 3.2.实现接口 4.插件的加载 4.1.静态插件 4.1.1.静态插件实现方式 4.1.2.静态插件加载的过程 4.1.3.示例 4.2.动态插件 4.2.1.动态插件的加载过程 5.定位插件 6.插件开发的优势 7.总结…

蓝桥杯高频考点-与日期相关的题目

文章目录 前言1. 如何枚举合法日期1.1 预存每个月的天数1.2 封装一个判断日期是否合法的函数1.3 枚举日期并判断日期是否合法 2. 判断日期是否为回文日期2.1 将日期当作字符串进行处理2.2 将日期当作一个8位数进行处理 3. 给定初始日期&#xff0c;计算经过n天后对应的日期3.1 …

Java集合【超详细】2 -- Map、可变参数、Collections类

文章目录 一、Map集合1.1 Map集合概述和特点【理解】1.2 Map集合的基本功能【应用】1.3 Map集合的获取功能【应用】1.4 Map集合的两种遍历方式 二、HashMap集合2.1 HashMap集合概述和特点【理解】2.2 HashMap的组成、构造函数2.3 put、查找方法2.4 HashMap集合应用案例【应用】…

另一棵树的子树(oj题)

一、题目链接 https://leetcode.cn/problems/subtree-of-another-tree/submissions/536304222 二、题目思路 1.首先遍历大树&#xff0c;判断大树的根结点的值是否等于小树的根结点的值&#xff0c;如果不相等&#xff0c;就找大树的左孩子或者右孩子&#xff0c;以左孩子为根…

博士毕业论文/CTEX/LATEX

LATEX环境安装 CTEX 安装 &#xff08;垃圾&#xff0c;不要装&#xff09; 运行 clean.batcomp.bat 缺少字体 Couldn’t find Adobe Heiti S.cfg’ miktex-maketfm: No creation rule for font “Adobe Heiti Std”.解决方法&#xff1a;其实就是下载这四个字体之后&…

jsp实验19 File

三、源代码以及执行结果截图&#xff1a; readJSPFile.jsp <% page contentType"text/html" %> <% page pageEncoding "utf-8" %> <% page import"java.io.*"%> <style> #tom{ font-family:宋体;font-size:2…

Crosslink-NX器件应用连载(10): 图像输入并通过HDMI输出

作者&#xff1a;Hello,Panda 大家下午好&#xff0c;晚上好。这里分享一个Lattice Crosslink-NX器件通过MIPI或LVDS输入图像&#xff0c;并通过HDMI输出图像的案例&#xff08;其实这是个比较冷门的需求&#xff0c;Crosslink-NX器件还是主要做MIPI桥接用&#xff09;。 咱们…