iOS组件化方案与实践:Target-Action

原文链接: https://www.jianshu.com/p/6ee3e8a50d47

目前项目组件化已经告一段落,我把总结的相关文章列罗出来
创建cocoapod私有库详细步骤(基础组件组件化)
iOS组件化方案与实践:Target-Action
iOS组件化解决图片显示问题
xib文件如何组件化(cocoapod私有库)?
适合小白的iOS项目组件化完整详细流程,每步都有demo
pod trunk push使用
iOS项目组件化遇到的问题及解决(100%遇得到)
Cocoapods 更新索引库或者指定第三方

概述

根据CTMediator写了个准备实施组件化的组件化前demo,以及完成组件化demo

我把对目前项目从零到组件化完成过程中遇到的问题总结在这里

如果你准备组件化的话,肯定遇得到(╯﹏╰)

一、demo结构

该方案基于Mediator和Target-Action模式组件化,通过运行时完成调用。简单来说:Mediator维护着若干个category,一个category对应一个target,一个target可以包含多个action。
可以这么理解:一个A业务组件包含一个category组件,这个category组件中有个Mediator的category,这个category中有一个target,这个target属于对应的A业务组件,target中会有若干接口方法,用来其他业务组件通过这个category获取到A业务组件中的业务。
所有组件都通过组件自带的Target-Action来响应,也就是说,模块与模块之间的接口被固化在了Target-Action这一层。
对CTMediator的详细解读可参考该文章

接下来介绍下本文demo,共包含两个模块:TAPersonInfo和TAPersonPrefrence,我在这里强制认为这是两个业务组件(别较真哈),这两个组件中有业务交互。
首页:

image.png

点击个人详情进入第一个业务组件TAPersonInfo:

image.png

点击开始打分按钮进入第二个业务组件TAPersonPrefrence:

image.png

点击喜欢或者烦之后返回第一个模块,并把选择的结果显示出来。

image.png

组件化之前和组件化之后的各个pod以及主工程demo我在下面给出,大家自行下载:
组件化之前主工程
TAPersonInfo业务地址
TAPersonInfo业务category地址
TAPersonPrefrence业务地址
TAPersonPrefrence业务category地址
存放索引文件(podspec)库
组件化完成后的主工程

下面介绍如何根据CTMediator实现本文demo。

1、主界面只有一个“个人详情”按钮,点击按钮进入个人详情模块TAPersonInfo。
通常实现方式为:
先在主页引入头文件

#import "WGPersonInfoViewController.h"

然后

    WGPersonInfoViewController *perCon = [[WGPersonInfoViewController alloc] init];
    [self.navigationController pushViewController:perCon animated:YES];

在个人页面进入个人偏好页面的方式与上述相同。
这么做没有什么不对,但当项目越来越大,从主页跳转的页面越来越多时,导入的头文件也会越来越多,进而导致多文件之间的相互依赖。在做组件化时不可能为了拆分组件而把头文件也引入进来,为做组件化造成困难。
为了解除业务组件之间的耦合,就要换种方式来实现。

2、Podfile中 pod 'CTMediator 把CTMediator引入工程中。

3、个人详情TAPersonInfo默认是一个单独模块,组件化时TAPersonInfo就是一个单独project,为了方便其他模块调用,我们需要先给TAPersonInfo建立一个对外提供服务的接口,即wgPersonInfoCatogeryKit分类。
我们从主页跳到个人详情页业务场景是:进入到个人详情页时需要传给此页面名字和年龄两个值,并在该页面显示。
实现如下:

image.png

.h文件中

#import <CTMediator/CTMediator.h>

@interface CTMediator (TAPersonInfo)

- (UIViewController *)personInfoWithName:(NSString *)name age:(NSInteger)age;

@end
.m文件中

#import "CTMediator+TAPersonInfo.h"

@implementation CTMediator (TAPersonInfo)

- (UIViewController *)personInfoWithName:(NSString *)name age:(NSInteger)age{
    
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
    [dic setValue:name forKey:@"name"];
    [dic setValue:@(age) forKey:@"age"];
    
    return [self performTarget:@"WGPersonInfoViewController" action:@"PersonInfoViewController" params:dic shouldCacheTarget:NO];
}

@end

主页面调用如下:

#import "CTMediator+TAPersonInfo.h"

......

- (void)btnClicked{
    UIViewController *con = [[CTMediator sharedInstance] personInfoWithName:@"寒江" age:18];
    [self.navigationController pushViewController:con animated:YES];
}

主页通过catogery入口,把需要传递的参数放到字典之中,然后调用CTMediator开源库performTarget: action:params: shouldCacheTarget方法,传递target(WGPersonInfoViewController)和action(PersonInfoViewController)名称以及参数字典,在.m文件中通过runtime让target执行action方法,完成具体场景功能。

image.png

image.png

细心地话,会发现tatget和action与传递过来的名称不一样,在前面多了一个前缀,这是因为在CTMediator中:

image.png

在target中可以引入WGPersonInfoViewController.h头文件是因为他们在一个模块中。

该target中的action返回需要的viewController,在主页面拿到viewController后就可以push到对应页面。

- (void)btnClicked{
    UIViewController *con = [[CTMediator sharedInstance] personInfoWithName:@"寒江" age:18];
    [self.navigationController pushViewController:con animated:YES];
}

4、从TAPersonInfo个人详情页进入第二个模块TAPersonPrefrence实现方式同上。

5、到此就完成了该demo的全部内容。

二、拆分业务,实现组件化

根据上述对项目结构的讲解,我们首先需要拆分出两个组件:TAPersonInfo和TAPersonPrefrence,同时为了组件之间的相互调用,还需要为这两个组件各建一个category组件,最后总共需要wgPersonInfoKit、wgPersonInfoCatogeryKit、wgPersonPrefenceKit、wgPersonPrefrenceCatogeryKit四个组件。

1、为了方便管理,我在github上新建一个organization,里面专门存放这次组件化的各个组件。

image.png

2、建立pod步骤在我的这篇文章中有非常详细的讲解,我的四个组件也是按照其中的步骤一步一步建立的。
这里我简单说下步骤和需要注意的地方:

. 新建一个repo索引文件库(用来存放xxx.podspec,包括远程和本地)。
. 新建wgPersonInfoKit 组件 (本地和远程)
. 新建wgPersonInfoCatogeryKit组件 (本地和远程)
. 新建wgPersonPrefenceKit组件(本地和远程)
. 新建wgPersonPrefrenceCatogeryKit 组件(本地和远程)
. 主工程pod 这四个组件,删除项目中的原本代码,运行即可。

注意:

1、依赖
新建wgPersonInfoCatogeryKit、wgPersonPrefrenceCatogeryKit、wgPersonPrefrenceCatogeryKit时和组件化基础组件不一样的地方在基础组件组件化时,代码中没有依赖其他第三方,所以在podspec文件中不需要有其他的第三方依赖,下图是我在基础组件组件化中生成的podspec文件,可看到里面没有第三方依赖。

image.png

在本文的这四个组件,wgPersonInfoCatogeryKit、wgPersonPrefrenceCatogeryKit依赖CTMediator开源库;wgPersonInfoKit依赖建好的组件wgPersonPrefrenceCatogeryKit;所以在修改podspec文件时,在文件最后需要加上依赖。我在下面给出这三个组件的podspec内容:
wgPersonInfoCatogeryKit和wgPersonPrefrenceCatogeryKit的podspec依赖部分:

image.png

wgPersonInfoKit的podspec依赖部分:

image.png

所以在组件化上传podspec文件时要把wgPersonPrefrenceCatogeryKit放在wgPersonInfoKit前面,不然验证不会通过。

2、验证:
把组件podspec索引文件上传索引库时会有验证步骤,在验证wgPersonInfoKit.podspec时可能会报如下错误:

image.png

报这个错的原因是校验podspec文件时默认只会到官方specs库(https://github.com/CocoaPods/Specs.git)去校验,这时候就需要同时指定自己创建的远程索引库地址库校验。

解决办法:

pod spec lint wgPersonInfoKit.podspec --verbose --allow-warnings --sources='[https://github.com/CocoaPods/Specs.git,https://github.com/wgModularization/WGModulSpecs.git](https://github.com/CocoaPods/Specs.git,https://github.com/wgModularization/WGModulSpecs.git)'

如图,验证通过。

image.png

3、pod四个组件

在主工程Podfile文件中:

pod 'wgPersonInfoKit'
pod 'wgPersonInfoCatogeryKit'
pod 'wgPersonPrefenceKit'
pod 'wgPersonPrefrenceCatogeryKit'

可能会报如下错误

image.png

原因是默认会从master的索引库查找,master里并没有该组件。
解决办法是需要指定组件远程索引库地址:

source 'https://github.com/wgModularization/WGModulSpecs.git'
source 'https://github.com/CocoaPods/Specs.git'

完整的Podfile如图:

image.png

这时候cd到主项目根目录后,执行pod install后会pod进入五个

image.png

这是因为组件中存在依赖关系,想查看这种依赖关系的话,也很简单,在主工程目录中,和Podfile在同一层级有一个

image.png

打开可看到依赖关系:

image.png

到此,主项目目录为:

image.png

到此,工程中已经没有了TAPersonInfo和TAPersonPrefrence两个模块,完成组件化。运行结果和没有组件化之前效果一样。

36人点赞

日记本



作者:wg刚
链接:https://www.jianshu.com/p/6ee3e8a50d47
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/qq_30513483/article/details/102745469
今日推荐