iOS组件化集成和开发实现

iOS组件化的应用我们采用了CTMediator方式实现, 以下是CTMediator作者的博客地址:
iOS应用架构谈 组件化方案
在现有工程中实施基于CTMediator的组件化方案

现在介绍组件化参照CTMediator作者实现的步骤, 本文可参照作者实现组件化方案结合使用

创建私有仓库和准备工作
  1. 先去开一个repo,这个repo就是我们私有Pod源仓库


    image.png
  2. pod repo add [私有Pod源仓库名字] [私有Pod源的repo地址]

  3. 创立一个文件夹,例如project。把我们的主工程文件夹放到project下:~/project/FengYingXin


    image.png
  4. 在~/project下clone快速配置私有源的脚本repo:git clone git@github.com:casatwy/ConfigPrivatePod.git

  5. 将ConfigPrivatePod的template文件夹下Podfile中source https://github.com/ModulizationDemo/PrivatePods.git改成第一步里面你自己的私有Pod源仓库的repo地址

  6. 将ConfigPrivatePod的template文件夹下upload.sh中PrivatePods改成第二步里面你自己的私有Pod源仓库的名字

一: 我们先创建JSIDCard Pod
  • 新建Xcode工程,命名为JSIDCard,放到projects下
  • 新建Repo,命名也为JSIDCard,新建好了之后网页不要关掉

然后cd到ConfigPrivatePod下,执行./config.sh脚本来配置JSIDCard这个私有Pod。脚本会问你要一些信息,Project Name就是JSIDCard,要跟你的JSIDCard工程的目录名一致。HTTPS RepoSSH Repo网页上都有,Home Page URL就填你JSIDCard Repo网页的URL就好了。

同样的,我们再创建JSIDCard_Category,因为它也是个私有Pod,所以也照样子跑一下config.sh脚本去配置一下就好了。
配置完成后, 你的项目应该如下所示

image.png

然后去JSIDCard_Category下,在Podfile中添加一行pod "CTMediator",在podspec文件的后面添加s.dependency "CTMediator",然后执行pod install --verbose

image.png

image.png

接下来打开JSIDCard_Category.xcworkspace,把脚本生成的名为JSIDCard_Category的空目录拖放到Xcode对应的位置下,然后在这里新建基于CTMediator的Category:CTMediator+JSIDCard。

到这里为止,JSIDCard工程和JSIDCard_Category工程就准备好了。


image.png
二:在主工程中引入JSIDCard_Category工程,并让主工程编译通过

去主工程的Podfile下添加pod "JSIDCard_Category", :path => "../JSIDCard_Category"来本地引用JSIDCard_Category。

然后编译一下,说找不到JSIDCardViewController的头文件。此时我们把头文件引用改成#import <JSIDCard_Category/CTMediator+JSIDCard.h>

然后继续编译,说找不到JSIDCardViewController这个类型。看一下这里是使用了JSIDCardViewController的地方,于是我们在Development Pods下找到CTMediator+JSIDCard.h,在里面添加一个方法:

- (UIViewController *)JSIDCard_aViewControllerWithParams:(NSDictionary *)params;
image.png

再去CTMediator+JSIDCard.m中,补上这个方法的实现:

然后我们把主工程调用JSIDCardViewController的地方改为基于CTMediator Category的实现:

 UIViewController *viewController = [[CTMediator sharedInstance] JSIDCard_aViewControllerWithParams:dic];
 [self.navigationController pushViewController:viewController animated:YES];

再编译一下,编译通过。

三:添加Target-Action,并让JSIDCard工程编译通过

我们在JSIDCard工程中创建一个文件夹:Targets,然后看到JSIDCard_Category里面有performTarget:@"JSIDCard",所以我们新建一个对象,叫做Target_JSIDCard。

然后又看到对应的Action是viewController,于是在Target_JSIDCard中新建一个方法:Action_JSIDCardViewController。这个Target对象是这样的:

头文件:
#import <UIKit/UIKit.h>

@interface Target_JSIDCard : NSObject

- (UIViewController *)Action_JSIDCardViewController:(NSDictionary *)params;

@end

实现文件:
#import "Target_JSIDCard.h"
#import "JSIDCardViewController.h"

@implementation Target_JSIDCard

- (UIViewController *)Action_JSIDCardViewController:(NSDictionary *)params;
{
    JSIDCardViewController *viewController = [[JSIDCardViewController alloc] init];
    return viewController;
}

@end

然后我们再继续编译JSIDCard工程,发现找不到JSCardInfoViewController。然后我们已同样的方式创建JSCardInfoViewController

创建JSCardInfo之后, 我们对应地在JSIDCard工程中修改头文件引用为#import <JSCardInfo_Category/CTMediator+JSCardInfo.h>,并且把调用的代码改为:

  UIViewController *viewController = [[CTMediator sharedInstance] JSCardInfo_viewControllerWithContentText:@"hello, world!"];
  [self.navigationController pushViewController:viewController animated:YES];

此时再编译一下,编译通过了。

四:收尾工作、组件发版

此时还有一个收尾工作是我们给JSCardInfo业务线创建了Category,但没有创建Target-Action。所以我们要去主工程创建一个JSCardInfo业务线的Target-Action。创建的时候其实完全不需要动到JSCardInfo业务线的代码,只需要新增Target_JSCardInfo对象即可:

arget_JSCardInfo头文件:
#import <UIKit/UIKit.h>

@interface Target_JSCardInfo : NSObject

- (UIViewController *)Action_viewController:(NSDictionary *)params;

@end

Target_JSCardInfo实现文件:
#import "Target_JSCardInfo.h"
#import "JSCardInfoViewController.h"

@implementation Target_JSCardInfo

- (UIViewController *)Action_viewController:(NSDictionary *)params
{
    NSString *contentText = params[@"contentText"];
    JSCardInfoViewController *viewController = [[JSCardInfoViewController alloc] initWithContentText:contentText];
    return viewController;
}

@end

接下来给这三个私有Pod发版
发版过程就是几行命令:

git add .
git commit -m "版本号"
git tag 版本号
git push origin master --tags
./upload.sh

最后,所有的Pod发完版之后,我们再把Podfile里原来的本地引用改回正常引用,也就是把:path...那一段从Podfile里面去掉就好了,改动之后记得commit并push。

组件化实施到此结束。

思路总结和说明

以下分为代码逻辑和操作逻辑来说明

代码逻辑:
组件化分开每个人员来看,其实步骤比较简单, 如果想理解并且单独完成组件化的过程就很容易晕, 下面对组件化的具体思路进行总结

在主项目中, JSIDCardViewController是一个要被拆分的模块, 那么他要被作为组件拆分出来, 就要在外面的创建一个JSIDCard_Category类以供外部调用, 和一个业务组件JSIDCard, JSIDCard_Category的具体内容实现

NSString * const kCTMediatorTargetJSIDCardCompleted = @"JSIDCard";
NSString * const kCTMediatorActionJSIDCardViewControllerr = @"JSIDCardViewController";

@implementation CTMediator (JSIDCard)
- (UIViewController *)JSIDCard_aViewControllerWithParams:(NSDictionary *)params{
    return [self performTarget:kCTMediatorTargetJSIDCardCompleted action:kCTMediatorActionJSIDCardViewControllerr params:params shouldCacheTarget:NO];
}

其中 performTarget: action: 方法是 CTMediator 组件的方法, 他主要是通过这个方法找到对应的业务组件(JSIDCard)中的文件名也是类名(Target_JSIDCard)和方法名(Action_JSIDCardViewController)
kCTMediatorTargetJSIDCardCompleted为类名, kCTMediatorActionJSIDCardViewControllerr方法名
而JSIDCard组件的方法实现如下

#import "Target_JSIDCard.h"
#import "JSIDCardViewController.h"

@implementation Target_JSIDCard
- (UIViewController *)Action_JSIDCardViewController:(NSDictionary *)params{
    JSIDCardViewController *idcardVC = [[JSIDCardViewController alloc] initWithUserChip:params[@"userChip"]];
    return idcardVC;
}

所以以上可以看出, JSIDCard_Category中的传递的类名和方法名(即自定义的静态变量kCTMediatorTargetJSIDCardCompletedkCTMediatorActionJSIDCardViewControllerr)必须与业务组件JSIDCard的类名和方法名完全一致

这里的一致是指下划线后面的名称

业务组件和分类组件的生成规则也是严格按照CTMediator组件的规则来创建, 即Target_AAA和CTMediator (AAA)的方式, 业务组件中的方法名称的生成规则为Action_BBB

CTMediator内部业务逻辑就会寻找调用Target_AAA的类和你传过来的方法名称BBB来寻找对应的业务组件和方法,而这个AAA一般就是你拆分组件的前缀名称, 例如示例中就是JSIDCard,

分类一般一个组件中JSIDCard_Category和业务组件JSIDCard为同一人所完成, 那么提供给同事时, 只要组件内部遵守CTMediator的命名规则确保分类能调用到业务组件中的方法, 只要把JSIDCard_Category中对外的方法提供给对接同事即可

操作逻辑:
因为
JSIDCard_Category采用Runtime形式来调用业务组件, 所以, JSIDCard_Category的Podfile文件中是不包含业务组件的, 只包含了CTMediator框架

# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'

source 'https://github.com/chenchangjian/PrivatePods.git'
source 'https://github.com/CocoaPods/Specs.git'

use_frameworks!

target 'JSIDCard_Category' do
 pod "CTMediator"
end

主项目中则两个组件全部包含

# open source
source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/chenchangjian/PrivatePods.git'

platform :ios ,'8.0'

def default_pods
  pod "JSIDCard_Category"
  pod "JSIDCard"
  pod "JSCardInfo_Category"
  pod "JSCardInfo"
end

target 'FengYingXin' do
  default_pods
end

同理, 如果有其他模块需要拆分为JSCardInfo_Category和JSCardInfo组件, 在JSIDCard 业务组件中调用就要包含JSCardInfo_Category, 主项目中也要再包含JSCardInfo_Category组件和JSCardInfo组件

# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'

source 'https://github.com/chenchangjian/PrivatePods.git'
source 'https://github.com/CocoaPods/Specs.git'

# use_frameworks!

target 'JSIDCard' do
 pod "JSCardInfo_Category"
end

总结

组件化开发是一个高效率工作的模式, 好处很多
其中包括同事之间配合互不影响, 没有代码冲突,少了SVN上解决代码冲突的可能性, 并且个人之间代码风格可按照个人最适应的风格开发,提高开发效率
测试可以减少测试的打包体积和测试人员快速测试, 可以单独打包某个组件供测试同事测试, 只有在最后上线前打包主干代码提测即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 某一天,老妈也开始了智能手机生活,开始刷朋友圈,给我发信息,推送各种鸡汤。 于是我也有幸发现了老妈隐藏在互联网时代...
    阿狂在日本阅读 362评论 0 3
  • 佛法讲“有求皆苦”,把目标放在外在,必定有苦,因为外在的因缘是自己无法主宰的,外在的一切也都是会改变的。 求不得,...
    落雨清枫阅读 523评论 0 1