一写在前面
前些时间听朋友说了一个话题, 利用 AOP 解耦细节业务, 确实有趣因为我们通常情况下说起 AOP, 都会想起比如埋点 method swizzing 等字眼, 角度比较宏观 AOP 国内开发者喜欢称之为面向切面编程, 其作为面向对象编程的一种补充, 在实际业务场景中发挥着巨大作用
喜欢看代码的可直接看 DEMO
AOP 局部解耦 DEMO
二为什么使用 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
来源: http://www.jianshu.com/p/fb9e0ee8fa82