iOS 我的组件化日记 part1:练嘴

1.什么是组件?

A.组件很类似功能模块,但会更细致一点.
B.其实不需要纠结单个组件到底是不是以对象实体的形式存在于内存中,因为不同的实现方式做法不一样.
C.组件化的精髓在于App工程内部拆分多个组件后,组件之间相互不引用对方的代码,组件调用组件由中间件统一调度,组件内页面跳转+组件间页面跳转也由中间件调度.

2.悲痛的教训

场景1:一个App项目中团队人员比较多,不同的人负责不同的模块开发,有的
人直接使用资源文件设计的,有的人用代码直接写的,有的人负责登录,有的
人负责订单,突然有一天搞订单的开发A找搞登录的开发B说要调一下登录,登
录成功以后你要再回调下我写的模块的方法告诉我成功登录,我要刷新一下订
单页面,B傻傻的就答应了,找B的人C、D、F....越来越多,B负责的代码越写
越多,同时A也不怎么开心,因为A发现调B写的登录要通过类实例化函数获取
模块,调C写的支付使用工厂方法,调D写的计算器组件又是另外一种写法,结
果A自己的代码也越来越丑。

场景1告诉我们:
没有中间件==>各自为战,相互伤害
有中间件==>各自为战,相安无事
深有体会

场景2:一个App里面有很多内嵌的H5页面,缠品A对猿B说,我们的活动页面
要调用一下我们的订单页面,用户如果下了一个订单成功以后H5要能够拿到反
馈有欢迎语,猿B和H5的开发猿C经过很久很久的讨论,确定了H5如果调用
App的订单页面,参数怎么传,订单提交以后怎么再调H5的接口,参数怎么定
义,各自把代码写到各自的项目里,没过多久缠品A说另外的H5要调用原生的
界面,怎么怎么个流程,推送点击要调用原生的某个页面,点完要反馈给后台
统计,兄弟App要跳转到我们的App某个页面跳转完成某个动作以后要再跳转
回去......猿B每每接到这样的需求就紧紧握住自己中箭的膝盖,收拾了一下写的
那么多代码,深藏功与名......🌚.

场景2告诉我们:
没有中间件==>业务代码混杂,代码复用率底下
有中间件==>业务分离,代码复用率高
体会不是那么深

3.如何拆分组件

3.1 基础功能组件

类似于性能统计、Networking、Patch、网络诊断等

按功能分库,不涉及产品业务需求,跟库Library类似
通过良好的接口拱上层业务组件调用;
不写入产品定制逻辑,通过扩展接口完成定制;

3.2 基础UI组件

产品内通用UI组件;(各个业务模块依赖使用,但需要保持好定制扩展的设计)
公共通用UI组件;(不涉及具体产品的视觉设计, 目前较少)

3.3 产品业务组件

例如:圈子、1元购、登录、客服MM等

4.各大门派的做法

4.1 蘑菇街的做法:

轮子>>MGJRouter

  • 页面跳转:
[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=10"]
  • 组件间功能调用:
    作者表述有两种方案:

<方案1>

//register
[MGJRouter registerURLPattern:@"mgj://cart/ordercount" toObjectHandler:^id(NSDictionary *routerParamters){
    // do some calculation
    return @42;
}];
//use
NSNumber *orderCount = [MGJRouter objectForURL:@"mgj://cart/ordercount"]

<方案2>
每个组件都是真实存在于内存中,所有组件归属于ModuleManager.组件间靠已经约定好的协议进行通信.(作者表述这种用的更广泛).

蘑菇街总结:(忽略MGJRouter实现组件间功能调用)MGJRouter只负责页面跳转.也就是说蘑菇街的方案中,Router(路由)只不过是组件化的一部分.

4.2 CTMediator的做法:

轮子>>CTMediator

ModuleA组件的所有方法写在分类CTMediator+CTMediatorModuleAActions中.

  • 页面跳转:
UIViewController *viewController = [[CTMediator sharedInstance] CTMediator_viewControllerForDetail];
[self.navigationController pushViewController:viewController animated:YES];
  • 组件间功能调用:
[[CTMediator sharedInstance] CTMediator_presentImage:[UIImage imageNamed:@"image"]];

CTMediator总结:简单粗暴.

4.3 网易的做法

轮子>>LDBusMediator

网易的做法的在使用外观上看上去和MGJ是一样的,不过不同的是MGJ采取的前置注册的策略,而网易采取的是后置询问的策略.

MGJ:
App launch 完成,建立各个组件所有页面与url的映射关系,建立各个组件所有协议与服务类的映射关系.
真正调用当然就像字典取值一样简单明了.

网易:
App launch 完成,各个组件只在中间件内设置一个点连接点.
到真正调用的时候,中间件通过遍历这些连接点询问各组件谁能对这个调用做出反应.

5.关于路由(Router)多说两句

5.1 岛内(App内)

大前端对Router的运用,在SPA上解决URL和UI的同步问题.

iOS端也有许多关于Router的轮子(HHRouter,JLRoutes,MGJRouter),功能大同小异,都是以URLPattern做键,存入一个block或者是以个VC的类名.

存取方式
JLRoutes:对URLPattern挨个匹配,返回结果(查找较慢)
HHRouter,MGJRouter:对URLPattern做打断,分级存储(查找较快)
存入类型
HHRouter:支持VC+block
MGJRouter,JLRoutes:只支持block

如果组件化用到了路由,个人意见:

App组件化专注于两个问题:
1.各个页面之间的跳转问题.
2.各个组件之间相互调用.

App内路由专注于:
各个页面之间的跳转问题.

就像上面提到的MGJRouter,采用Router还是用于页面跳转,不怎么用与组件间的调用.用url来指定跳转到那个页面无论是iOS,安卓,web是相通的.而且三端都走一套逻辑,在App上线突然遇到了紧急bug,就发布动态降级成H5或者一个本地的错误界面.
反观用Router打开url来调用方法外加获取返回值(如:NSNumber *orderCount = [MGJRouter objectForURL:@"mgj://cart/ordercount"]),混杂于上面Router协调页面跳转的逻辑中真的是有一种怪怪的感觉.

路由只不过是组件化的一部分.
5.2 岛外(App外)

Route should be:
Scheme + module + VC + param

上面的讨论全在App内,所以只有module + VC + param,现在看看Scheme.

将App内的逻辑公布于外(Share your App with the world),一个Scheme就可以进入你的App.

一个app==>孤岛
一片app==>群岛

群岛内岛与岛用Scheme跳转,具体到具体的互通业务则是岛内Route与岛内Route的对接.


看完组件是什么,如何拆分组件,各大门派的做法后,我在现有的大工程内效仿MGJ,工程内加入MGJRouter+加了一个协议映射服务类的中间件.全局页面跳转不再写push+present,A模块调用B模块的方法也不再直接调用,组件化完成了!!!本宝宝还太年轻


文章参考:
Limboy>蘑菇街 App 的组件化之路
Casa>iOS应用架构谈 组件化方案
iOS组件化实践方案-LDBusMediator炼就
iOS 组件化 —— 路由设计思路分析
带你一步步构建iOS路由
移动端路由层设计

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 93,750评论 266 518
  • 原文链接:https://github.com/halfrost/Halfrost-Field/blob/mast...
    hament阅读 5,738评论 1 31
  • 前言 随着用户的需求越来越多,对App的用户体验也变的要求越来越高。为了更好的应对各种需求,开发人员从软件工程的角...
    一缕殇流化隐半边冰霜阅读 87,623评论 214 1,098
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 174,812评论 25 709
  • 大抵每个农村出来的人,都有一种故乡情结,伴随着这种情结的还有萦绕着的,淡淡的乡愁。这种情结,在三十岁以上的人群中尤...
    兰石轩主阅读 627评论 2 7