iOS程序犭袁ios专题ios

iOS组件化(中篇)-拆分业务组件

2017-09-17  本文已影响4136人  我阿郑

        在上一篇中对基础组件进行了拆分,接下来会拆分业务组件。业务组件最简单的理解(比如,有3个tabbar专题、作者、商城三个模块,就可以理解成3个业务组件)。功能组件也很好理解,比如我们项目中用到的轮播器、播放器、图片浏览器等都可以单独抽出功能组件。

在拆分业务组件之前,需要了解组件间通信的概念?笔者这里要说的是业务组件间的通信。比如专题组件A、作者组件B、点击专题A组件中cell的作者头像图标跳转到B组件中“作者详情”的界面。这就是简单的组件间通信,假如不允许直接import引入依赖,该怎么进行跳转?

关于组件间的通信的几种方式以及利弊《这篇文章》已经说的很详细了。笔者采用的就是文章中提出的基于Mediator模式和Target-Action模式组件化方案,中间采用了runtime来完成调用。基于Mediator模式和Target-Action模式组件化方案如下图所示,会用到开源库CTMediator

由上图可见,专题A组件和作者B组件都对外提供了一个Target的API类(Target_A和Target_B),  同时需要为A组件和B组件创建对应的A_category组件和B_category组件(Category组件依赖CTMediator库),Category组件需要提供A_CTM分类、和B_CTM分类,A_CTM分类、和B_CTM分类里的方法对应了这个Target下所有可能的调用场景,这样调用者在包含mediator的时候,自动获得了所有可用的Target-action,无论是调用还是参数传递,都非常方便。为什么是Category而不是其他 。

以下内容摘自《iOS应用架构谈 组件化方案》


1. category本身就是一种组合模式,根据不同的分类提供不同的方法,此时每一个组件就是一个分类,因此把每个组件可以支持的调用用category封装是很合理的。

2. 在category的方法中可以做到参数的验证,在架构中对于保证参数安全是很有必要的。当参数不对时,category就提供了补救的入口。

3. category可以很轻松地做请求转发,如果不采用category,请求转发逻辑就非常难做了。

4. category统一了所有的组件间调用入口,因此无论是在调试还是源码阅读上,都为工程师提供了极大的方便。

5. 由于category统一了所有的调用入口,使得在跨模块调用时,对于param的hardcode在整个App中的作用域仅存在于category中,在这种场景下的hardcode就已经变成和调用宏或者调用声明没有任何区别了,因此是可以接受的。



接下来一步步实现业务组件拆分

1. 首先远程和本地创建专题组件A和作者组件B。

2. 通过pod lib create在本地创建相应的代码模版.同样把special、author文件夹拖入到对应的FFSpecialKit、FFAuthorKit的classes路径下面。

3. 修改.podspec索引文文件和Podfile文件后执行pod install,修改ReactiveCocoa和Result的UseLegacySwiftLanguage Version 设置成YES。

修改podspec索引文件 添加依赖 修改podfile

4. 编译此时会报错各种文件找不到。新建一个FFSpecialKit.h的文件专门引入头文件。然后将原来#import “public.h” 替换成#import “FFSpecialKit.h"

5.  再次编译会报下面的文件找不到,然后先将“FFAuthorDetailController”,“FFAuthorListReformer”这几个文件相关的代码注释了.再次编译会报下面的错误,然后同样将相关代码注释掉编译就OK了。

6.  FFSpecialKit组件编译通过之后,按照同样的方式处理FFAuthorKit组件并使其编译通过.接下来为组件FFSpecialKit 和FFAuthorKit创建对应的Target_Special和Target_Author文件(创建完之后执行一次pod insall)

```

#import < Foundation/Foundation.h >

#import "FFAuthorKit.h"

@interface Target_Author :NSObject

/// FFAuthorDetailViewController控制器

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

///返回转化好的Reformer对象

- (NSDictionary*)Action_authorReformerWithOriginData:(NSDictionary*)params;

/// Reformer对象

- (NSDictionary *)Action_authorReformer:(NSDictionary*)params;

/// Request对象

- (APIRequest*)Action_authorAPIRequest:(NSDictionary*)params;

@end

```

```

#import"Target_Author.h"

#import"FFAuthorDetailController.h"

#import"FFAuthorListReformer.h"

#import"AuthorAPIRequest.h"

@implementationTarget_Author

- (UIViewController*)Action_authorDetailViewController:(NSDictionary*)params {

return[[FFAuthorDetailControlleralloc]init];

}

- (NSDictionary*)Action_authorReformerWithOriginData:(NSDictionary*)params {

FFAuthorListReformer*reformer = [[FFAuthorListReformeralloc]init];

returnparams ? [reformerreformData:params] :nil;

}

- (NSDictionary *)Action_authorReformer:(NSDictionary*)params {

return[[FFAuthorListReformeralloc]init];

}

- (APIRequest*)Action_authorAPIRequest:(NSDictionary*)params {

return[[AuthorAPIRequestalloc]init];

}

@end

```

```

#import

#import"FFSpecialKit.h"

@interfaceTarget_Special :NSObject

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

- (NSDictionary*)Action_specialReformerWithOriginData:(NSDictionary*)params;

- (NSDictionary *)Action_specialReformer:(NSDictionary*)params;

- (APIRequest*)Action_specialAPIRequest:(NSDictionary*)params;

@end

```

```

#import"Target_Special.h"

#import"FFSpecialDetailController.h"

#import"FFSpecialListReformer.h"

#import"SpecialAPIRequest.h"

@implementationTarget_Special

- (UIViewController*)Action_specialDetailViewController:(NSDictionary*)params {

return[[FFSpecialDetailControlleralloc]init];

}

- (NSDictionary*)Action_specialReformerWithOriginData:(NSDictionary*)params {

FFSpecialListReformer*reformer = [[FFSpecialListReformeralloc]init];

returnparams ? [reformerreformData:params] :nil;

}

- (NSDictionary *)Action_specialReformer:(NSDictionary*)params {

return[[FFSpecialListReformeralloc]init];

}

- (APIRequest*)Action_specialAPIRequest:(NSDictionary*)params {

return[[SpecialAPIRequestalloc]init];

}

@end

```

7. 接下来就该创建对应的FFSpecialKit_Category 和FFAuthorKit_Category组件了。

8. 修改FFSpecialKit_Category对应的podspec文件和Podfile文件.

9. 创建对应的CTMediator+Special分类(创建分类时的存储路径需要注意一下)

```

#import <UIKit/UIKit.h>

#import <CTMediator/CTMediator.h>

#import <FFAPIsKit/APIRequest.h>

#import <FFAPIsKit/FFReformProtocol.h>

@interfaceCTMediator (Special)

- (UIViewController*)specialDetailController;

- (NSDictionary*)specialReformerWithOriginData:(NSDictionary*)data;

- (NSDictionary *)specialReformer;

- (APIRequest*)specialAPIRequest;

@end

```

```

#import"CTMediator+Special.h"

@implementationCTMediator (Special)

- (UIViewController*)specialDetailController {

return[selfperformTarget:@"Special"action:@"specialDetailViewController"params:nilshouldCacheTarget:NO];

}

- (NSDictionary*)specialReformerWithOriginData:(NSDictionary*)data {

return[selfperformTarget:@"Special"action:@"specialReformerWithOriginData"params:datashouldCacheTarget:NO];

}

- (NSDictionary *)specialReformer {

return[selfperformTarget:@"Special"action:@"specialReformer"params:nilshouldCacheTarget:NO];

}

- (APIRequest*)specialAPIRequest {

return[selfperformTarget:@"Special"action:@"specialAPIRequest"params:nilshouldCacheTarget:NO];

}

@end

```

10. 编译通过,按照同样的方式修改FFAuhtorKit_Category的podspec文件和Podfile文件,创建对应的CTMediator+Ahthor分类(创建完之后记得先pod install一下);然后编写分类分类内容如下.

```

#import <UIKit/UIKit.h>

#import <CTMediator/CTMediator.h>

#import <FFAPIsKit/APIRequest.h>

@interfaceCTMediator (Author)

- (UIViewController*)authorDetailViewController;

- (NSDictionary*)authorReformerWithOriginData:(NSDictionary*)data;

- (NSDictionary *)authorReformer;

- (APIRequest*)authorAPIRequest;

@end

```

```

#import"CTMediator+Author.h"

@implementationCTMediator (Author)

- (UIViewController*)authorDetailViewController {

return[selfperformTarget:@"Author"action:@"authorDetailViewController"params:nilshouldCacheTarget:NO];

}

- (NSDictionary*)authorReformerWithOriginData:(NSDictionary*)data {

return[selfperformTarget:@"Author"action:@"authorReformerWithOriginData"params:datashouldCacheTarget:NO];

}

- (NSDictionary *)authorReformer {

return[selfperformTarget:@"Author"action:@"authorReformer"params:nilshouldCacheTarget:NO];

}

- (APIRequest*)authorAPIRequest {

return[selfperformTarget:@"Author"action:@"authorAPIRequest"params:nilshouldCacheTarget:NO];

}

@end

```

11. 到此都创建完毕之后就可以提交FFSpecialKit_Category和FFAuhtorKit_Category组件了.还是通过下面步骤提交组件.


-  git add .

- git commit -m “xxx"

- git remote add origin 远程代码仓库地址

- git push origin master

- git tag 版本号 (注:这里的版本号必须和podspec里写的版本号一致)

- git push --tags


12. 通过pod spec lintFFSpecialKit.podspec - -verbose - -allow-warnings 验证索引文件的有效性,这里需要说明一些细节问题,验证时会报下面的错误.

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

解决如下:pod spec lint FFSpecialKit.podspec --verbose --allow-warnings --sources='https://github.com/FFComponent/FFSpecs.git,https://github.com/CocoaPods/Specs.git

继续验证报下面的错误

解决办法:在终端输入**`echo "2.3" > .swift-version` **

继续通过上面的命令验证,报下面的错误.

解决办法:

第一步:回到FFSpecialKit.h 导入到文件

第二步: 将原来**#import “FFSpecialListReformerKeys.h"** 的地方注释掉,替换成**#import“FFSpecialKit.h"**

第三步:编译一下组件,编译通过后,需要重新修改一下**FFSpecialKit.podspec**文件中的版本号,重新提交,重新打tag(上一次tag是1,这次tag累加为2) (因为代码做了修改,所以需要重新提交)

第四步:提交并打好tag后,再次进行验证就ok了.

第五步:最后,通过pod repo push ...提交索引文件就完成了。

按照上面的方式提交组件FFAuthorKit,都提交成功之后回到项目FlowerField_Component,然后修改Podfile文件,然后执行pod install.

安装完成之后,编译运行.

中篇到这里就结束了,最后需要说明一下,因为点击专题cell时跳转过去的详情界面,我特意用了XIB。这里点击cell进行跳转操作时会奔溃,具体如何去处理组件化过程中XIB以及一些图片资源,我将在下一篇中详细说明。再次感谢您的阅读。欢迎大家评论交流。

上一篇下一篇

猜你喜欢

热点阅读