AppDelegate的模块化+瘦身
前言
关于iOS
的模块化,要追溯到16年接触的BeeHive
了,BeeHive
将功能模块化,以module
的形式进行构建,以performSelector:
的形式进行module
的事件响应,以protocol
的形式进行module间的通信。可以说思路非常清晰明了了。关于BeeHive
的代码传送门alibaba/BeeHive,star已3.2k,关于BeeHive源码解析可参考霜神文章传送门BeeHive —— 一个优雅但还在完善中的解耦框架。实际上我并不认为BeeHive
可以真正用到我们项目中来,它确实构建了module
,但是module实例
带来的内存问题会让人头疼。个人认为将BeeHive
思想中的module
部分改造一下用在我们的AppDelegate
中是完全可行的。下面进入正文。
目录
一、模块拆分
二、模块事件响应
三、模块管理
1.模块注册
2.触发event
3.移除module
四、总结
一、模块拆分
画了一个结构图,module1到module4为我们需要在Appdelegate中进行处理的业务逻辑,比如说我们的数据库处理
,分享功能
,推送功能
等等。
首先为所有模块定义了三个接口:
@protocol SHRMAppEventModuleProtocol <UIApplicationDelegate>- (NSInteger)moduleLevel;
- (void)destroyModule;
- (NSString *)moduleID;@end
复制代码
接口定义了三个函数,moduleLevel
返回module执行的优先级,destroyModule
用来对module进行释放,moduleID
返回当前module的id。接口的默认实现统一在BaseAppEventModule
中进行。BaseAppEventModule
为所有module的父类,只有继承了BaseAppEventModule
的module才能被管理。
关于BaseAppEventModule
的默认实现也很简单,对module进行销毁的时候用到了SHRMAppEventModuleManager
下面会讲到,优先级默认设置100.
@interface SHRMBaseAppEventModule : NSObject <SHRMAppEventModuleProtocol>@end#define MODULE_LEVEL_DEFAULT 100
@implementation SHRMBaseAppEventModule- (NSInteger)moduleLevel {return MODULE_LEVEL_DEFAULT;
}- (void)destroyModule {[[SHRMAppEventModuleManager sharedInstance] removeModule:[self moduleID]];NSLog(@"%@ destroy",NSStringFromClass([self class]));
}- (NSString *)moduleID {return NSStringFromClass([self class]);
}@end
复制代码
模块的创建上面说到了必须要继承自SHRMBaseAppEventModule
,只有继承了SHRMBaseAppEventModule
的module才会被管理,因为只有SHRMBaseAppEventModule
遵循了SHRMAppEventModuleProtocol
协议。关于module创建部分:
@interface testMudule : SHRMBaseAppEventModule
@end@implementation testMudule- (NSInteger)moduleLevel {return 1;
}- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[self initMudule];[self destroyModule];return YES;
}- (void)initMudule {NSLog(@"testMudule init");
}@end
复制代码
application: didFinishLaunchingWithOptions:
函数的实现展示了一个module的整个生命周期,从创建到销毁的过程,那么application: didFinishLaunchingWithOptions:
是怎么响应的,实际上module的头文件并没有暴漏任何接口,到这里就实现了功能的模块化
。那为什么还能执行到这里,这要感谢强大的runtime
函数performSelector:
,下面讲一下我对module
事件响应的处理。
二、模块事件响应
还是以上面的application: didFinishLaunchingWithOptions:
函数为例,它是怎么来的,很明显这是AppDelegate
里面的APP生命周期回调:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[[SHRMAppEventModuleManager sharedInstance] handleApplicationEvent:@selector(application:didFinishLaunchingWithOptions:)Complete:^(id _Nonnull module, SEL _Nonnull sel) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"[module performSelector:selwithObject:applicationwithObject:launchOptions];
#pragma clang diagnostic pop}];return YES;
}
复制代码
没看错,这样一搞AppDelegate
的application: didFinishLaunchingWithOptions:
就剩这些了,这样一来,所有实现了application: didFinishLaunchingWithOptions:
的modlue都会被调用,调用优先级根据接口定义的moduleLevel
返回值确定。到这里我们就完成了AppDelegate瘦身
的工作,实际上AppDelegate中的其他回调处理是一样的。当然还有一个很重要的没有说,就是SHRMAppEventModuleManager
做了什么,通过上面的结构图能够看到SHRMAppEventModuleManager
是个中间件,用来处理module与AppDelegate间的关系。下面说到第三部分,模块管理。
三、模块管理
SHRMAppEventModuleManager
为一个单例,提供了三个接口:
/**初始化所有的AppDelegate相关的Event Modules*/
- (void)registedAllModules;/**触发event module处理AppDelegate回调事件@param eventSel AppDelegate 回调事件消息@param complete module处理handle*/
- (void)handleApplicationEvent:(SEL)eventSelComplete:(void(^)(id module,SEL sel))complete;/**移除module对象@param moduleID module ID*/
- (void)removeModule:(NSString *)moduleID;
复制代码
1.模块注册
模块注册的思路是完全按照BeeHive
的思想来的,在编译期就将我们的module
通过__attribute
函数进行注册。在运行期再将我们注册好的module
取出来在registedAllModules
中进行实例化,按照level
的返回值进行排序存储。__attribute
函数具体做了什么可以参考我之前的文章写一个易于维护使用方便性能可靠的Hybrid框架(三)—— 配置插件关于插件注册部分的解释。
2.触发event
handleApplicationEvent:Complete:
为module事件响应的核心函数:
- (void)handleApplicationEvent:(SEL)eventSelComplete:(void(^)(id module,SEL sel))complete {NSMutableArray *tmpAppEventModules = [[NSMutableArray alloc] initWithArray:self.appEventModules];for (id<SHRMAppEventModuleProtocol>module in tmpAppEventModules){if ([module conformsToProtocol:@protocol(SHRMAppEventModuleProtocol)]){if ([module respondsToSelector:eventSel]) {if (complete) {complete(module,eventSel);}}}}
}
复制代码
if ([module respondsToSelector:eventSel])
就会执行complete
将module
和sel
返回,也就是到了AppDelegate
里面,继而执行module
的sel
函数,并且将参数传递过去。
3.移除module
module
的移除,在AppDelegate
里面,我们将程序启动之后调用完就不再使用的功能module会手动执行移除操作。这也是前言所说的BeeHive在module移除这一块会稍显复杂,但是在AppDelegate里面,我们是完全可以知道哪些module在加载之后可以立即移除的,另外我们仅在AppDelegate中进行模块化,产生的module实例也会非常少,so,完全没必要担心module所带来的内存开销问题。
- (void)removeModule:(NSString *)moduleID {NSInteger index = NSNotFound;NSInteger resIndex = 0;for (id<SHRMAppEventModuleProtocol>module in self.appEventModules){if ([[module moduleID] isEqualToString:moduleID]){index = resIndex;break;}resIndex++;}if (index != NSNotFound) {[self.appEventModules removeObjectAtIndex:index];}
}
复制代码
总结
最后总结一下,关于模块化,现在总体来看比较流行,也有很多介绍模块化,组件化具体实施之路的文章,都很优秀,也值得学习。关于解耦,我更倾向于protocol
的方式,接口protocol
化,代码易读且清晰。之前看过mrpeak
在组件化方面的文章,传送门iOS 组件化方案,个人觉得protocol+version
的方案和BeeHive
非常像,protocol
解耦,version
进行module
的版本管理,但是还是没有解决module
所带来的内存开销问题,module
一旦细化,何时销毁也是让开发者头疼的问题。先说这么多,各位小伙伴有任何问题欢迎评论区讨论。
最后附上DEMO传送门:AppDelegateMudule,欢迎star?。
AppDelegate的模块化+瘦身相关推荐
- AppDelegate瘦身指南
原文链接:http://kyson.cn/index.php/archives/105/ AppDelegate瘦身是一个大家都很熟悉的话题,各家也有各自的解决方案.但方案无外乎两种,一种是从AppD ...
- 基于clang插件的一种iOS包大小瘦身方案
引子 \ 包瘦身,包瘦身,包瘦身,重要的事情说三遍. \ 最近公司一款iOS APP(本文只讨论使用Objective C开发的iOS安装包)一直在瘦身,我们团队的APP也愈发庞大了.而要解决这个问题 ...
- newduba首页怎么去掉_京喜小程序首页瘦身实践
前言 在 web 开发场景,减少代码体积虽然是性能优化的一个方向,还没到锱铢必较的程度.但是在小程序场景,由于代码包上传阶段限制了主包 2M 和总包 16M(近期微信官方正在内测将总包上限调整至 20 ...
- iOS应用程序瘦身的静态库解决方案
为什么要给程序瘦身? 随着应用程序的功能越来越多,实现越来越复杂,第三方库的引入,UI体验的优化等众多因素程序中的代码量成倍的增长,从而导致应用程序包的体积越来越大.当程序体积变大后不仅会出现编译流程 ...
- 京东商城iOS客户端安装包瘦身实践
一.概述 随着业务的快速增加,商城app的大小也在迅速增加,一度超过了300M.安装包大小的不断增加对app下载成本,推广效率产生了比较大的影响.从2018年9月份我们对商城app开始了为期二期的专项 ...
- JDK14+JAVAFX14+Maven定制jre打包瘦身,必成版
注: 本教程jdk9以上版本通用(任何java项目都可以通过本教程精简jre) 博客来由: jdk9以后代码模块化逐渐成为趋势,jlink工具开始出现在人们的视野中,它可以用来定制项目所需要的jre, ...
- iOS安装包瘦身的那些事儿
在我们提交安装包到App Store的时候,如果安装包过大,有可能会收到类似如下内容的一封邮件: 收到这封邮件的时候,意味着安装包在App Store上下载的时候,有的设备下载的安装包大小会超过100 ...
- [MaxCompute MapReduce实践]通过简单瘦身,解决Dataworks 10M文件限制问题
用户在DataWorks上执行MapReduce作业的时候,文件大于10M的JAR和资源文件不能上传到Dataworks,导致无法使用调度去定期执行MapReduce作业. 解决方案: 第一步:大于1 ...
- SpringBoot 部署 Jar 文件,瘦身优化指南 !
以下文章来源方志朋的博客,回复"666"获面试宝典 作者 | Java基基 来源 | https://mp.weixin.qq.com/s/Y5VK7TI1TQBN6O-k5O6h ...
最新文章
- Python3.5模块‘OS’‘sys’
- insert执行时oracle如何处理,ORACLE中Insert时字符处理
- Eclipse旧版本Luna SR2(版本4.4.2)下载地址
- Spring Boot 整合 Netty(附源码)
- 《他其实没那么喜欢你》经典台词
- [Pytorch].pth转.pt文件
- linux windows主题下载官网,Linux Deepin 15.10.2 桌面kwin主题App美化
- 消息发送和接收基本应用
- 视频预训练界的HERO!微软提出视频-语言全表示预训练模型HERO,代码已开源!...
- 工厂支持多数据库开发的三层结构模式随笔(一)
- BZOJ 2288: 【POJ Challenge】生日礼物 优先队列+贪心+链表
- mysql数字辅助表_关于数字的经典SQL编程问题:数字辅助表
- 如何实现音频合成立体声录制?
- 博途PLC和ABB变频器PN通讯详解
- NET Framework 4 与.NET Framework 4 Client Profile有什么区别?
- mysql drop表明_MySQL DROP TABLE会完全删除表还是仅删除结构?
- manjaro上安装独显驱动(双显卡切换)的正确方法
- 加州房价篇 (三) : 模型的训练,评估和房价的预测
- Android网卡网速测试
- Facebook 申请蓝色认徽章