iOS架构:AOP实现局部模块化(附Demo)
点击上方“iOS开发”,选择“置顶公众号”
关键时刻,第一时间送达!
一、写在前面
前些时间听朋友说了一个话题,利用 AOP 模块化细节业务,确实有趣。因为我们通常情况下说起 AOP,都会想起比如“埋点”、“method swizzing”等字眼,角度比较宏观,起到了解耦的作用;本文从另一个角度出发,使用 AOP 思想对细节业务做模块分离的工作。
AOP 国内开发者喜欢称之为面向切面编程,其作为面向对象编程的一种补充,在实际业务场景中发挥着巨大作用。
二、为什么使用 AOP
面向切面编程,也可以理解为面向功能面编程,将某一特定的功能视为一个切面,不但可以复用代码,还可以使代码逻辑更加清晰,更符合单一功能设计原则。
在 iOS 开发中,经常会有这种需求,比如需要记录进入每一个控制器的次数。最次的方案就是在每一个控制器的viewWillApear:方法里面写记录代码;稍优一点的方案是在基类的viewWillApear:里面写记录代码,但是这种方法有个弊端就是只有继承于基类的控制器才能记录到,不友好;而最优的方式就是利用runtime的method swizzing交换方法,hook住viewWillApear:在里面做记录逻辑。
当然,本文是为了解决另外一个问题。
在 iOS App 中,MVC 和 MVVM 是比较流行的架构模式,而当某个界面业务量达到一个程度过后,MVVM 甚至是 VIPER 模式都显得有些力不从心,为了达到更高层次的模块化,往往会做其他方面的工作,比如讲Scrollview等代理的配置独立出来,然而这种方式仍然有个弊端,那就是代理方法里面的逻辑太多导致独立出来的类仍然臃肿。
所以,这就是写这篇文章的目的,提供一种更深层次的模块化的方案。
三、实际应用
其实之前我对 AOP 的思想还不是很了解,后来发现其实我已经在之前的框架中有了应用,实现该架构实现的主要技术点是:利用方法重定向实现多接收者的方法转发。
详情可看这篇文章,文章中间部分有对消息转发流程的简述:
iOS解决方案:文本输入控制(献上框架)
本文就不讲解消息发送机制了,在 Demo 中有封装 —— YBAOPManager,我们将利用它来做局部模块化。
在实际业务需求中,出场率很高的是UITalbeView和UICollecitonView等需要用大量代理方法配置的视图,当然这是苹果程序设计的惯例。当UI界面很复杂,业务逻辑相当多的时候,虽然把网络请求、数据处理、视图封装等都模块分离出去了,但是配置代理里面的逻辑太多,我们想要每一个类处理一部分代理方法。
Demo 以 UITableView 为例。
首先,创建实现 UITableView 代理的三个类:
@implementation TestTableViewDigitConfig
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80;
}
@end
@implementation TestTableViewClickConfig
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"click -- section:%ld, row:%ld", indexPath.section, indexPath.row);
}
@end
@implementation TestTableViewCellConfig
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(UITableViewCell.class)];
if (!cell) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:NSStringFromClass(UITableViewCell.class)];
}
cell.textLabel.text = [NSString stringWithFormat:@"第%ld行", indexPath.row];
return cell;
}
@end
如代码所见,这里将 tableView 的代理用三个类来分别实现,然后在 UIViewController 里面只需要写这些代码:
@interface TestVC ()
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) YBAOPManager *aopManager;
@property (nonatomic, strong) TestTableViewDigitConfig *digitConfig;
@property (nonatomic, strong) TestTableViewClickConfig *clickConfig;
@property (nonatomic, strong) TestTableViewCellConfig *cellConfig;
@end
@implementation TestVC
#pragma mark life cycle
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
}
#pragma mark getter
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
_tableView.tableFooterView = [UIView new];
_digitConfig = [TestTableViewDigitConfig new];
_clickConfig = [TestTableViewClickConfig new];
_cellConfig = [TestTableViewCellConfig new];
_aopManager = [YBAOPManager new];
[_aopManager addTarget:_digitConfig];
[_aopManager addTarget:_clickConfig];
[_aopManager addTarget:_cellConfig];
_tableView.delegate = _aopManager;
_tableView.dataSource = _aopManager;
}
return _tableView;
}
@end
核心代码就是将 YBAOPManager 类的使用:
当你需要使用多个对象(target)来承接一些方法的实现,初始化 YBAOPManager 实例,将这些对象实例添加到
YBAOPManager 实例中(addTarget),最后将 YBAOPManager 实例作为这些方法的第一承接者。剩下的方法分发工作就交给该类了。
代码请看 DEMO,不复杂。
AOP 局部模块化 DEMO(https://github.com/indulgeIn/YbAOPCuttingModule)
作者:indulge_in
链接:https://www.jianshu.com/p/fb9e0ee8fa82
iOS开发整理发布,转载请联系作者授权
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
随时掌握互联网精彩
- 1 习近平G20里约峰会展现大国担当 7981419
- 2 多国驻乌克兰大使馆因袭击风险关闭 7901931
- 3 78岁老太将减持2.5亿股股票 7822614
- 4 二十国集团里约峰会将会卓有成效 7747882
- 5 俄导弹击中乌水电站大坝 7627216
- 6 孙颖莎王艺迪不敌日本削球组合 7553981
- 7 高三女生酒后被强奸致死?检方回应 7462288
- 8 第一视角记录虎鲨吞下手机全程 7321127
- 9 手机不能看医院CT图像就要少收费 7214532
- 10 智慧乌镇点亮数字经济新未来 7191393