围观神仙打架,反革命工程师《iOS应用架构谈 组件化方案》和蘑菇街Limboy的《蘑菇街 App 的组件化之路》的阅读指导
原文:http://reviewcode.cn/article.html?reviewId=20
围观神仙打架,反革命工程师《iOS应用架构谈 组件化方案》和蘑菇街Limboy的《蘑菇街 App 的组件化之路》的阅读指导
最近质量最高的文章应该就是上述3篇和Bang关于三篇的解析文章。
地址分别为:
《iOS应用架构谈 组件化方案》
《蘑菇街 App 的组件化之路》
《蘑菇街 App 的组件化之路·续》
《iOS 组件化方案探索》 from Bang
我的文章只是就一些技术细节做一些分析。 毕竟我不是架构师,很多东西我属于大概知道如何实现,但是我不明白这样做到底为什么。毕竟层次有差距。
第一部分:名词解释
问题一:何为利用URL的方式打开ViewController?
这是入门问题。如果这个问题看不懂,看这两篇基本等同于看天书。
简单举个例子。
首先,看一下一个Node.js服务端如何处理一个get请求。
http://weibo.com/u/1438670852/home?topnav=1&wvr=6
这是个登录之后的微博的首页URL。其实服务端拿到这个url之后可以利用一些中间件,例如bodyparser之类的把url解析了。比如。你可以这样获得topnav的值和wvr的值。
- app.get(’http://weibo.com/u/:userid/home’, function(req, res) {
- var topnav = req.body[”topnav”];
- var wvr = req.body[”wvr”];
- });
那么,其实蘑菇街的组件化方案的其中一个功能就是仿照服务端解析URL的方式来处理ViewController之间的跳转。
蘑菇街是怎么做的?
- 注册Class。在
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中先使用单例MGJRouter
注册所有的ViewController的Pattern,也即VC的模板,你可以想象成是一个字符串对应一个Block,这个block里面包含了生成ViewController的代码和需要的赋值的参数。比如上述的DetailViewController可以描述成这样。
- [MGJRouter registerURLPattern:@"mgj://detail?name=:name&summary=:summary" toHandler:^(NSDictionary *routerParameters) {
- NSString *name = routerParameters[@"name"];
- NSString *summary = routerParameters[@"summary"];
- // create view controller with id
- // push view controller
- }];
这样注册了之后,这个MGJRouter单例里就储存了这个ViewController.单例里无非就是有一个可变字典的property,
比如有一个NSMutableDictionary *routers
,然后呢。
[[routers setObject:block forKey:url];]
这样就注册了。
那么,怎么用?
既然有了存的方法,那自然有取得方法。
比如。[MGJRouter openURL:@"mgj://detail?name=:name&summary=:summary" withParam:@{@"name": @"zql", @"summary":@"wuyanzu" }];
这样,只需要在字典里通过URL取得block,然后将参数填进去就行了。 如果还是不理解看这个开源库。
routable-ios
问题二:什么是上下文
?
几篇文中都大量的出现了上下文
这个关键字。上下文到底是什么? 上下文对应的英文单词是Context。对此比较好理解解释的是轮子哥的下面这段话。
每一段程序都有很多外部变量。只有像Add这种简单的函数才是没有外部变量的。一旦你的一段程序有了外部变量,这段程序就不完整,不能独立运行。你为了使他们运行,就要给所有的外部变量一个一个写一些值进去。这些值的集合就叫上下文。
看代码。
- DetailViewController *detailVC = [DetailViewController alloc] init];
- detailVC.name = @"xxx";
- detailVC.summary = @"xxx";
- [XX.navigationController detailVC];
这就叫没有剥离上下文。
why?
因为你为了使这个页面跳转,你必须要给DetailVC传一些值。传的这些值就构成了上下文。
大家注意这段话。
然而这款方案有一个很小的缺陷在于对param的key的hardcode,这是为了达到最大限度的解耦和灵活度而做的权衡。在我的网络层架构和持久层架构中,都没有hardcode的场景,这也从另一个侧面说明了组件化架构的特殊性。
我为什么要把反革命工程师里总结的这句话贴出来,因为这句话很重要。后面会提到。
问题三:什么叫去Model化?
举个例子。有个ModelA
- ModelA *model = [[ModelA alloc] init];
- ViewControllerA *a = [[ViewControllerA alloc] init];
- a.model = model;
- [self.navigationController pushViewController:a animated:YES];
所以从当前页面跳转到a这个控制器的时候需要传入一个ModelA的实例。那么如果ModelA因为业务逻辑的变更,有一个属性没了,或者改名字了,或者加了什么property。
那么,你就需要在所有的工程文件里凡是引用了这个Model的文件里都check一遍。防止发生问题。这就没有解耦。
为了防止这种情况,我们在这种情况下,就需要去Model化(那Model还有什么用?)。 比如你的ViewControllerA需要传入5个值。那你就老老实实的别传Model。一个个传值。
第二部分:流程
理解
大家注意看反革命工程师的Demo.地址
Demo大概架构如下。
ok,现在大脑放空,我们来按流程走一遍。
我们来拿下厨房举例。
首先如图所示。我们到了这个页面。
我们姑且起名字叫做WeekPopularViewController
.
然后,点击任意一个Cell,我们会跳转到这个页面。
我们给这个页面起名叫RecipeDetailViewController
.
那么,我们现在按照反革命工程师设计的架构来写一遍这个流程。
1.创建Target-Action,我们创建一个Target_RecipeDetail
.在这个文件里,我们主要生成我们的RecipeDetailViewController
和为我们生成的VC进行一些必要的赋值。例如。
- - (UIViewController *)Action_RecipeDetailViewController:(NSDictionary *)params
- {
- RecipeDetailViewController *viewController = [[RecipeDetailViewController alloc] init];
- viewController.valueLabel.text = params[@"key"];
- return viewController;
- }
2.创建CTMediator的Category.CTMediator+CTMediatorRecipeDetailActions
.这个Category利用Runtime调用我们刚刚生成的Target_RecipeDetail
,注意这个Category神奇的地方,由于利用了Runtime,导致我们完全不用#import
刚刚生成的Target即可执行里面的方法,所以这一步,两个类是完全解耦的。也即是说,我们在完全解耦的情况下生成了我们需要的ViewController。例如。
- - (UIViewController *)CTMediator_viewControllerForRecipeDetail
- {
- UIViewController *viewController = [self performTarget:kCTMediatorTargetA
- action:kCTMediatorActionNativFetchDetailViewController
- params:@{@"key":@"value"}];
- if ([viewController isKindOfClass:[UIViewController class]]) {
- // view controller 交付出去之后,可以由外界选择是push还是present
- return viewController;
- } else {
- // 这里处理异常场景,具体如何处理取决于产品
- return [[UIViewController alloc] init];
- }
- }
3.由于在Target中,传递值得方式采用了去Model化得方式,导致我们在整个过程中也没有#import任何Model。所以,我们的每个类都与Model解耦。
4.那么,跳转的操作也就顺理成章的可以使用类似于
- UIViewController *viewController = [[CTMediator sharedInstance] CTMediator_viewControllerForRecipeDetail];
- [self presentViewController:viewController animated:YES completion:nil];
这样的方法执行。
注意了,整个流程你居然只需要在WeekPopularViewController
import一个CTMediator+CTMediatorRecipeDetailActions
。
这就是牛逼的地方了。
我看到这里简直想大喊wocao,牛逼
。
这里其实唯一的问题就是反革命工程师自己提出来的,Target_Action里不得不填入一些Hard Code。就是对创建的VC的赋值语句。因为想想一下,二次接手的人可能并不知道新创建的VC需要赋哪些值,这就造成了可能会在填入参数列表的时候出错。 或许还有人看的懵懵懂懂。
那么我提一个问题。
如果现在上头有个任务,需要你把项目中的任何一个VC都封装成这样。
随便拎出来一个ViewController,它自带体系。不需要#import任何别的VC,最多也就是import少量的Model就能单个使用。
你应该怎么做?
带着这个问题看,估计会好理解一点。
我写这篇文章是灰常灰常痛苦的。
为啥,因为层次不够。看了不下20边,很多都属于知其然不知其所以然。其实看到现在我感觉也就理解了30%不到的样子,架构师这个职位确实牛逼。
术和势的区别啊。
</div>
围观神仙打架,反革命工程师《iOS应用架构谈 组件化方案》和蘑菇街Limboy的《蘑菇街 App 的组件化之路》的阅读指导相关推荐
- iOS应用架构谈 组件化方案
简述 前几天的一个晚上在infoQ的微信群里,来自蘑菇街的Limboy做了一个分享,讲了蘑菇街的组件化之路.我不认为这条组件化之路蘑菇街走对了.分享后我私聊了Limboy,Limboy似乎也明白了问题 ...
- 五,iOS应用架构谈 组件化方案
简述 前几天的一个晚上在infoQ的微信群里,来自蘑菇街的Limboy做了一个分享,讲了蘑菇街的组件化之路.我不认为这条组件化之路蘑菇街走对了.分享后我私聊了Limboy,Limboy似乎也明白了问题 ...
- iOS应用架构谈(5) 组件化方案
简述 前几天的一个晚上在infoQ的微信群里,来自蘑菇街的Limboy做了一个分享,讲了蘑菇街的组件化之路.我不认为这条组件化之路蘑菇街走对了.分享后我私聊了Limboy,Limboy似乎也明白了问题 ...
- iOS应用架构谈-组件化方案
iOS应用架构谈-开篇 iOS应用架构谈-view层的组织和调用方案 iOS应用架构谈-网络层设计方案 iOS应用架构谈-本地持久化方案及动态部署 iOS应用架构谈-组件化方案 简述 前几天的一个晚上 ...
- iOS组件化方案的几种实现
最近研究了一下项目的组件化,把casa.bang.limboy的有关组件化的博客看了一遍,学到了不少东西,对目前业界的组件化方案有了一定的了解.这些高质量的博客大致讨论了组件化的三种方案:url-bl ...
- iOS应用架构谈 网络层设计方案--RTNetworking
iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方案 iOS应用架构谈 本地持久化方案及动态部署 iOS应用架构谈 组件化方案 https:/ ...
- iOS 应用架构谈:view 层的组织和调用方案
iOS 应用架构谈:view 层的组织和调用方案 iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方案 iOS应用架构谈 动态部署方案 iOS应用架构 ...
- iOS应用架构谈 网络层设计方案
iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方案 iOS应用架构谈 本地持久化方案及动态部署 iOS应用架构谈 组件化方案 前言 网络层在 ...
- iOS开发系列--iOS应用架构谈
转自:Casa Taloyum 目录 iOS应用架构谈 (一)开篇 iOS应用架构谈 (二)view层的组织和调用方案 iOS应用架构谈 (三)网络层设计方案 iOS应用架构谈 (四)动态部署方案 i ...
- iOS应用架构谈 view层的组织和调用方案
iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方案 iOS应用架构谈 本地持久化方案及动态部署 iOS应用架构谈 组件化方案 前言 < ...
最新文章
- NVIDIA DRIVE AGX开发工具包
- 探测Windows2K/XP/2003本机系统信息
- VMware View 5.0 Ready! 资源汇总(持续更新)
- Spring MVC——ConverterltString, Dategt DEMO
- 解决mapgis比例尺不正确问题
- 下拉刷新和UITableView的section headerView冲突的原因分析与解决方案
- 《善用佳软:高效能人士的软件应用之道》一2.3 思维导图:思想脉络的逻辑结构...
- linux抓本来端口包,Linux抓包
- 三国演义 制作词云 2------python
- 请启封,您的双态IT大会邀请函
- AXURE RP 原型图绘制手册
- ESP32实现Wave(.wav)音频文件输出
- 学生信息管理系统 C++实现
- 为什么要开发问卷调查APP?
- satoken+ gateway网关统一鉴权 初版
- 算法设计与分析——Johnson Trotter算法
- 软件工程教程:第2章软件问题定义及可行性分析 课后习题
- 捅了“蚂蚁窝”?怎么大家都在唱《蚂蚁呀嘿》
- 环形缓冲区ringbuffer c++类模版实现
- 爬虫爬取快递100网查快递信息
热门文章
- 浅谈Linux PMIC驱动(一)
- android音乐搜索功能实现,撸个应用学Android——空灵音乐本地音乐版
- hotmail接收邮件服务器(pop),Microsoft微软邮箱 outlook、hotmail 打开pop和imap的方法
- 无线测温传感器、无线测温装置在项目上的应用—安科瑞 孙斌
- happen-before原则解读
- Android一些控件上显示的英文字母都被转为大写字母的原因分析及问题解决
- No valid Maven installation found
- CAS号:2417213-21-7以(ZPS-PVPA)为催化剂载体
- itext7生成pdf页脚页码
- clock()、time()、clock_gettime()和gettimeofday()函数的用法和区别【转】