ios业务模块间互相跳转的解耦方案
*此文章需有一点runtime的知识,假设你不了解runtime,《高速理解Runtime of Objective-C》:
问题:
一个app通常由很多个模块组成,全部模块之间免不了会相互调用,比如一个读书管理软件,可能会有书架、用户信息、图书详情等等模块,从用户信息-我读的书中,能够打开图书详情。而在图书详情-所在书架,又能够打开书架。
一般这样的需求我们可能会这实现:
/*用户信息模块*/
#import "UserViewController.h"
#import "BookDetailViewController.h" @implementation UserViewController
//跳转到图书详情
+ (void)gotoBookDetail {
BookDetailViewController *detailVC = [[BookDetailViewController alloc] initWithBookId:self.bookId];
[self.navigationController.pushViewController:detailVC animated:YES];
}
@end
项目初期还好,速度快,够简单。可是项目发展到一定程度时,问题就来了,每一个模块都离不开其它模块,互相依赖粘在一起:
图1:模块依赖关系。箭头方向表示依赖,比方:Discover依赖BookDetail
解决方式:
遇到这样的情况,最直接的方法就是添加一个中间件,各个模块跳转通过中间件来管理。这样。全部模块仅仅依赖这个中间件。可是中间件怎么去调用其它模块那?好吧,中间件又会依赖全部模块。
好像除了添加代码的复杂度,并没有真正解决不论什么问题。
引入中间件的代码:
/*用户信息模块*/
#import "UserViewController.h"
#import "Mediator.h” @implementation UserViewController
//跳转到图书详情
+ (void)gotoBookDetail {
[Mediator gotoBookDetail:self.bookId];
}
@end /*中间件*/
#import “Mediator.h”
#import “BookDetailViewController.h" @implementation Mediator
//跳转到图书详情
+ (void)gotoBookDetail:(NSString *)bookid {
BookDetailViewController *detailVC = [[BookDetailViewController alloc] initWithBookId:bookId];
[self.navigationController.pushViewController:detailVC animated:YES];
}
@end
引入中间件的依赖关系:
图2:引入中间件的依赖关系
有没有一种方法,能够完美的解决这个依赖关系那?我们希望做到:每一个模块之间互相不依赖,而且每一个模块能够脱离project由不同的人编写、单独编译调试。以下的方案通过对中间件的改造,非常好的攻克了这个问题,解决后的模块间依赖关系例如以下:
图3: 比較理想的模块间依赖关系
实现方法:
我们通过一个实际的样例来分析一下。
请先下载demo并打开:https://github.com/zcsoft/ZC_CTMediator
先看一下文件夹结构,对整个project的组织结构有一个大致的了解,然后结合后面的结构图和每一个类的说明、以及project代码,来详细分析详细实现:
文件夹结构:
[CTMediatorproject文件夹]
|
|-[CTMediator]
| |-CTMediator.h.m
| |-[Categories]
| |-[ModuleA]
| |-CTMediator+CTMediatorModuleAActions.h.m
|
|-[DemoModule]
| |-[Actions]
| | |-Target_A.h.m
| |-DemoModuleADetailViewController.h.m
|
|-AppDelegate.h.m
|-ViewController.h.m
说明:
[CTMediator]
负责跳转的中间件,全部模块间跳转都通过这个模块来完毕。
[DemoModule]
一个样例模块。假设我们要从其它业务(ViewController.h.m)中跳转到这个业务模块。
在这个demo中,我们的目的是从其它业务(ViewController.h.m中)跳转到DemoModule业务模块。
全部模块的引用关系如图:
图4:demo中个模块的引用关系
因为demo中仅仅是从ViewController.h.m中跳转到DemoModule模块。所以仅仅须要ViewController.h.m依赖CTMediator,CTMediator到DemoModule模块的调用是使用执行时完毕了(图片中的蓝线),在代码中不须要相护依赖。也就是说。假设一个模块不须要跳转到其它模块。就不须要依赖CTMediator。
执行时的时序:
图5:隐藏了模块内实现细节的引用关系
调用关系概述:
首先由ViewController.h.m发起调用请求给CTMediator。CTMediator通过runtime去调用目标模块DemoModule,目标模块DemoModule依据參数创建自己的一个实例。并把这个实例返回给CTMediator。CTMediator在把这个实例返回给ViewController.h.m(此时ViewController.h.m不须要知道这个实例的详细类型,仅仅须要知道是UIViewController的子类),然后由ViewController.h.m决定以什么样的方式去展示DemoModule。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" width="544" height="425" />
图6: 完整的调用关系
调用关系详细解释:
1: ViewController.m发起调用请求给CTMediator(CTMediator+CTMediatorModuleAActions.m)。
ViewController.m-57行
UIViewController *viewController = [[CTMediator sharedInstance] CTMediator_viewControllerForDetail];
2: CTMediator+CTMediatorModuleAActions.m通过定义好的參数调用CTMediator。因为CTMediator+CTMediatorModuleAActions是CTMediator的扩展,所以能够直接使用self来调用CTMediator的实现。CTMediator+CTMediatorModuleAActions.m-行23
UIViewController *viewController =
[self performTarget:kCTMediatorTargetA
action:kCTMediatorActionNativFetchDetailViewController
params:@{@"key":@"value"}];
3: CTMediator依据CTMediator+CTMediatorModuleAActions.m传过来的目标和參数发起实际调用。这个调用关系是在执行时完毕的。所以此处并不须要在代码上依赖被调用者。假设被调用者不存在,也能够在执行时进行处理。CTMediator.m-93行
return [target performSelector:action withObject:params];
4/5: Target_A创建一个DemoModuleADetailViewController类型的实例(这个实例是Target_A通过DemoModuleADetailViewController类的alloc/init创建的)。Target_A.m-20行
DemoModuleADetailViewController *viewController = [[DemoModuleADetailViewController alloc] init];
6: Target_A返回创建的实例到CTMediator.m(发起时是通过runtime,步骤3),返回后CTMediator.m并不知道这个实例的详细类型,也不会对这个类进行不论什么解析操作,所以CTMediator.m跟返回的实例之间是没有不论什么引用关系的。
Target_A.m-23行
7: CTMediator.m返回步骤6中得到的实例到CTMediator+CTMediatorModuleAActions.m(发起时是步骤2)。CTMediator.m-93行
8: CTMediator+CTMediatorModuleAActions.m会将步骤7返回的实例当作UIViewController处理。接下来会在执行时推断这个实例的类型是不是UIViewController(是不是UIViewController的子类)。然后将得到的UIViewController交给调用者ViewController.m(由ViewController.m负责以何种方式进行展示)。
CTMediator+CTMediatorModuleAActions.m-行29
全部类的功能例如以下:
CTMediator.h.m
功能:指定目标(target。类名)+动作(action,方法名)。并提供一个字典类型的參数。CTMediator.h.m会推断target-action能否够调用,假设能够。则调用。因为这一功能是通过runtime动态实现的,所以在CTMediator.h.m的实现中。不会依赖不论什么其它模块,也不须要知道target-action的详细功能,仅仅要target-action存在。就会被执行(target-action详细的功能由DemoModule自己负责)。
CTMediator.h里实际提供了两个方法,分别处理url方式的调用和target-action方式的调用。当中,假设使用url方式,会自己主动把url转换成target-action。
CTMediator+CTMediatorModuleAActions.h.m
功能:CTMediator的扩展,用于管理跳转到DemoModule模块的动作。
其它模块想要跳转到DemoModule模块时。通过调用这个类的方法来实现。
可是这个类中。并不真正去做跳转的动作,它仅仅是对CTMediator.h.m类的封装,这样用户就不须要关心使用CTMediator.h.m跳转到DemoModule模块时详细须要的target名称和action名称了。
‘CTMediator.h.m’+‘CTMediator+CTMediatorModuleAActions.h.m’共同组成了一个面相DemoModule的跳转,而且它不会在代码上依赖DemoModule,DemoModule是否提供了对应的跳转功能,仅仅体如今执行时能否够正常跳转。至此,CTMediator这个中间层实现了全然的独立,其它模块不须要预先注冊。CTMediator也不须要知道其它模块的实现细节。唯一的关联就是须要在‘CTMediator+CTMediatorModuleAActions.h.m’中写明正确的target+action和正确的參数,而且这些action和參数仅仅依赖于Target_A.h.m。action和參数的正确性仅仅会在执行时检查。假设target或action不存在。能够在‘CTMediator.h.m’中进行对应的处理。
既:CTMediator不须要依赖不论什么模块就能够编译执行。
Target_A.h.m
提供了跳转到DemoModule模块的对外接口,与CTMediator+CTMediatorModuleAActions.h.m相互对应,能够说它仅仅用来为CTMediator+CTMediatorModuleAActions.h.m提供服务,所以在实现CTMediator+CTMediatorModuleAActions.h.m时仅仅须要參考Target_A.h.m就可以,足够简单以至于并不须要文档来辅助描写叙述。其它模块想跳转到这个模块时,不能直接通过Target_A.h.m实现。而是要通过CTMediator+CTMediatorModuleAActions.h.m来完毕。
这样,就实现了模块间相互不依赖,而且仅仅有须要跳转到其它模块的地方,才须要依赖CTMediator。
DemoModuleADetailViewController.h.m
DemoModule模块的主视图,这个样例中。会从ViewController.h.m跳转到这个模块。
AppDelegate.h.m
APP入口,从应用外通过Scheme跳入程序时会经过这个类。
ViewController.h.m
APP主视图,须要在这里跳转到DemoModule模块。
@转载请包涵以下全部信息
參考资料:
1: 方案来自:http://casatwy.com/iOS-Modulization.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
感兴趣的前往阅读原文。
2: 本文同一时候也參考了:http://blog.cnbang.net/tech/3080/
欢迎大家关注我:iDevShare
或加我微信:lofocus
ios业务模块间互相跳转的解耦方案的更多相关文章
- iOS开发,应用间的跳转
预习:URL由两部分组成-- 1.scheme:协议头(http:// ftp:// 等等) 2.path:路径(URL中path可以没有) 一.简单实现跳转到指定APP(也就是说跳转到的APP必须 ...
- iOS应用程序开发之应用间的跳转(用着微信等第三方分享登陆)
简介 配置和实现 判断应用启动方式 一.简介 最实际项目开发中,我们难免会遇到需要从一个应用跳转到另一个应用的情况.比如微信分享,实际就是一种应用间的跳转.但是有时候我们需要实现自己的两个应用间的跳转 ...
- 【转】iOS开发--一步步教你彻底学会『iOS应用间相互跳转』
1. 应用间相互跳转简介 在iOS开发的过程中,我们经常会遇到需要从一个应用程序A跳转到另一个应用程序B的场景.这就需要我们掌握iOS应用程序之间的相互跳转知识. 下面来看看我们在开发过程中遇到的应用 ...
- iOS - 白名单应用间相互跳转
1. 应用间相互跳转简介 在iOS开发的过程中,我们经常会遇到需要从一个应用程序A跳转到另一个应用程序B的场景.这就需要我们掌握iOS应用程序之间的相互跳转知识. 下面来看看我们在开发过程中遇到的应用 ...
- iOS应用程序开发之应用间的跳转
简介 配置和实现 判断应用启动方式 一.简介 最实际项目开发中,我们难免会遇到需要从一个应用跳转到另一个应用的情况.比如微信分享,实际就是一种应用间的跳转.但是有时候我们需要实现自己的两个应用间的跳转 ...
- React Native项目集成iOS原生模块
今天学习一下怎么在React Native项目中集成iOS原生模块,道理和在iOS原生项目中集成React Native模块类似.他们的界面跳转靠的都是iOS原生的UINavigationContro ...
- JS判断是否是微信页面,判断手机操作系统(ios或android)并跳转到不同下载页面
JS判断客户端是否是iOS或者Android 参考:http://caibaojian.com/browser-ios-or-android.html function is_weixin() { v ...
- Hadoop总结篇之五---模块间是怎么驱动执行的
在MRv1中,各个模块间驱动运行的方式是函数调用的方式.这是同步的过程,上一模块调用下一模块函数后,等待其执行.效率不高. 在MRv2中做了改进,yarn基于事件驱动的并发模型.在详细介绍前,先看下图 ...
- 初探linux内核编程,参数传递以及模块间函数调用
一.前言 我们一起从3个小例子来体验一下linux内核编程.如下: 1.内核编程之hello world 2.模块参数传递 3.模块间 ...
随机推荐
- Cordova 开发环境搭建及创建第一个app
整理记录使用cordova创建app应用程序并将其部署至Android系统移动设备上操作过程,具体如下: 一.前期安装环境 1. 安装JDK(java开发工具包) 2. 安装gradle 3. 安装A ...
- 深入理解Redis——(总纲)
前言 Redis这个东西,我来来回回的也搞了好几遍,之前更偏向于实战,很多时候只知其然而不知其所以然,最近借阅了一本<深入理解Redis>,就系统的整理一下. 为何选择Redis 开源免费 ...
- BZOJ 4195 程序自动分析
4195: [Noi2015]程序自动分析 Description 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3,-代表 ...
- pgsql 远程机器无法连接数据库报错处理方法
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本地localhost访问正常,在相同网段的远程机器访问报如下错误 “server closed the connection unexpe ...
- Java上传视频
页面: 上传文件时的关键词:enctype="multipart/form-data" <%@ page language="java" import=& ...
- 【PostgreSQL-9.6.3】函数(3)--日期和时间函数
在PostgreSQL中,DATE.TIME.TIMESTAMP是三种不同的数据类型.DATE表示日期类型,格式为YYYY-MM-DD或YYYYMMDD:TIME表示时间类型,格式为hh:mi:ss: ...
- chrome设置以及hosts备份
最近重装完chrome总是忘记改了哪些设置,所以这里做一下备份. 有卡顿问题可以关闭GPU加速 使用https的方式访问Google,Chrome下强制Google使用https的方法如下: 打开Ch ...
- NSURLCredential 代表认证结果证书?
NSURLCredential 代表认证结果证书?
- springMvc学习地址新
http://www.admin10000.com/document/6436.html 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar ...
- SPLAY or SPALY ?
写在前面: 由我们可爱的Daniel Sleator和Robert Tarjan提出的一种数据结构,平衡树的一种,本质是二叉树. 至于到底是splay还是spaly,我认为可能splay更对一些 毕竟 ...