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路由
移动端路由层设计

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

推荐阅读更多精彩内容

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