iOS组件化思路-大神博客研读和思考

2016.03.10 蘑菇街App的组件化之路: http://limboy.me/ios/2016/03/10/mgj-components.html

为什么要组件化?
  • 组件和组件之间没有明确的约束;

  • 组件单独开发、单独测试,不能揉入主项目中开发,测试也可以针对性的测试;

如何管理短链?(url跳转)

[MGJRouter registerURLPattern:@“mgj://detail?id=:id” toHandler:^(NSDictionary *routerParameters) {

NSNumber *id = routerParameters[@“id”];

// create view controller with id

// push view controller

}];

[MGJRouter openURL:@"mgj://detail?id=404”]

短链如何管理?

  1. 后台专门管理短链;平台生成所需的文件,ios平台生成h,m文件,android生成java文件,注入到项目中;

  2. 开发人员查看生成文件了解所有可用URL;

  3. 缺点:无法把参数传递也通过生成方式获得;

同步的Action调用?(服务调用)

方法一:通过url的方式

[MGJRouter registerURLPattern:@“mgj://cart/ordercount” toObjectHandler:^id(NSDictionary *routerParamters){

// do some calculation

return @42;

}]

NSNumber *orderCount = [MGJRouter objectForURL:@"mgj://cart/ordercount”]

方法二:通过protocol-class对应的方式

把公共协议文件统一放到PublicProtocolDomain.h中,所有业务组件只依赖这个文件;protocol只能通过类方法提供?

@protocol MGJCart

  • (NSInteger)orderCount;

@end

[ModuleManager registerClass:MGJCartImpl forProtocol:@protocol(MGJCart)]

[ModuleManager classForProtocol:@protocol(MGJCart)]

组件生命周期的管理:(组件管理)

启动初始化时,实例APP中所有组件的module实例,让每个组件的module实例执行一遍didFinishLaunchingWithOptions方法:在这方法中每个组件注册自己的URL,使用class注册;每个组件可以自行监控系统的通知,如UIApplicationDidBecomeActiveNotification, 对于没有系统通知消息则将此方法写入module的protocol中,依次执行实例的这些protocol方法;

[[ModuleManager sharedInstance] loadModuleFromPlist:[[NSBundle mainBundle] pathForResource:@“modules” ofType:@“plist”]];

NSArray *modules = [[ModuleManager sharedInstance] allModules];

for (id module in modules) {

if ([module respondsToSelector:_cmd]) {

[module application:application didFinishLaunchingWithOptions:launchOptions];

}

}

组件化版本管理的问题
  1. 版本同步问题: API接口改动升级(旧接口不存在了,不向下兼容),版本的中位号发生改变;需要所有依赖其的调用都发生改变,才能保证壳工程和主工程能够同步编译通过;

  2. pod update之后编译太长: 考虑通过framework的方式进行修改;

  3. 持续集成问题: 不能只是把podspec直接扔到private repo里完事,需要扔到主工程进行打包编译,编译通过允许提供版本升级,不通过扔回去进行处理;CI编译检查,通过之后再将版本号升级到private repo中,同时修改主工程中Podfile的版本依赖号; 但如果是其它工程呢,被多个业务工程所依赖,如何办?

蘑菇街开源组件:

MGJRouter: https://github.com/mogujie/MGJRouter.git

  1. JLRoutes 的问题主要在于查找 URL 的实现不够高效,通过遍历而不是匹配。还有就是功能偏多。

  2. HHRouter 的 URL 查找是基于匹配,所以会更高效,MGJRouter 也是采用的这种方法,但它跟 ViewController 绑定地过于紧密,一定程度上降低了灵活性。

(2)反革命的组件化方案
文章来源:
蘑菇街的方案为什么不好?
  • url注册对于实施组件化是完全没有必要的,拓展性和可维护性都降低;

  • 基于openURL的方案的话,有一个致命缺陷:非常规对象无法参与本地组件间调度;但是可以通过传递params来解决,但是这样区分了远程调用和本地调用的入口;

  • 模块内部是否仍然需要使用URL去完成调度?是没有必要的,为啥要复杂化?

反革命的组件化方案:

基于Mediator模式和Target-Action模式:

[CTMediator sharedInstance]

openUrl:url] //call from other app with url

parseUrl

performTarget:action:params //call form Native Module

runtime

[TargetA action1], [TargetA action2]

[TargetB action1], [TargetB action2]

反革命组件化方案的调用方式:

本地跨组件间调用:

[[CTMediator sharedInstance] performTarget:targetName action:actionName params:@{…}]

远程应用调用:

openUrl + parseUrl的方式; 针对请求的路由操作,直接将Target和Action的名字封装到url中;

反革命组件化方案的好处:
  1. 将远程调用和本地调用做了拆分,而且由本地应用调用位远程应用调用提供服务;

  2. 组件仅通过Action暴露可调用接口;

  3. 组件化方案必需去Model设计:只有调用方依赖Mediator,响应方依赖是没有必要的;

  4. 调用方如何知道接收方需要哪些Key的参数,如何知道有哪些target可被调用?:在mediator中维护针对Mediator的Category,每个category对应一个target,categroy中的方法对应Action场景;

  • category为组合模式,根据不同的分类提供不同的方法,每个组件对应一个category分类;

  • 参数验证和补救入口;

  • 轻松的请求转发;

  • 统一了所有组件间调用入口;

  • param的hardcode在整个app的作用域仅仅存在于category中,跟调用宏差不多;

  • 安全保证,对url中进行native前缀验证;

  • 保证动态调度考虑;

反革命组件化方案开源Demo:

代码Git地址:https://github.com/casatwy/CTMediator.git

二、实际项目中的组件化问题


(1) 为什么要组件化?
  • 解决人多(更好的协作)、需求多(更好的功能模块划分)的问题;

  • 解决项目模块间的代码耦合问题;(坚决抵制业务组件间代码直接引用)

(2)如何拆分组件?(神仙们讨论的主要是产品业务组件化的问题)
  • 基础功能组件:(类似于性能统计、Networking、Patch、网络诊断等)

  • 按功能分库,不涉及产品业务需求,跟库Library类似

  • 通过良好的接口拱上层业务组件调用;

  • 不写入产品定制逻辑,通过扩展接口完成定制;

  • 基础UI组件:(例如下拉刷新组件、iCausel类似的组件)

  • 产品内通用UI组件;(各个业务模块依赖使用,但需要保持好定制扩展的设计)

  • 公共通用UI组件;(不涉及具体产品的视觉设计, 目前较少)

  • 产品业务组件:(例如圈子、1元购、登录、客服MM等)

  • 业务功能间相对独立,相互间没有Model共享的依赖;

  • 业务之间的页面调用只能通过UIBus进行跳转;

  • 业务之间的逻辑Action调用只能通过服务提供;

(3)组件化工程需要解决的问题?
  • 组件化页面跳转(UIBus)方案要求:

  • 能够传递普通参数(系统基础数据类型)和复杂参数(url无法负载的对象),不负责CustomModel的传递处理;

  • 能够获取url对应的controller进行TabController的动态配置;

  • 能够对controller的present方式进行定制;

  • url的注册须用代码完成,必需去中心化处理;

  • 组件服务化(ServiceBus)方案要求:

  • 能够传递普通参数和复杂参数,尽量不使用CustomModel的传递;

  • 通过接口文件的统一基础库进行依赖;(业务开发方开发阶段只需要依赖接口文件依赖库,在主项目集成测试阶段依赖所有业务组件进行测试)

  • 接口和实现类的的对应注册须用代码完成,由中间件去控制服务实现类的生成;

(通用问题:复杂参数传递 key值的硬编码问题)

(4)组件维护问题?

三、关于组件化的思考和总结


文末

如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。

同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

前端面试题汇总

JavaScript

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值