iOS 干货整理Fuck iOS EveryDay

iOS组件化集成和开发实现

2018-10-15  本文已影响143人  陈长见

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

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

创建私有仓库和准备工作
  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

然后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上解决代码冲突的可能性, 并且个人之间代码风格可按照个人最适应的风格开发,提高开发效率
测试可以减少测试的打包体积和测试人员快速测试, 可以单独打包某个组件供测试同事测试, 只有在最后上线前打包主干代码提测即可

上一篇 下一篇

猜你喜欢

热点阅读