咱们之前聊过 AOP 模式相关的内容,这次给大家介绍的 Aspects 是对 AOP 模式的一个实践,也许从此你会喜欢上 AOP。
AOP 是一种帮助你将代码逻辑变得更清晰的设计模式, 咱们前面的文章中讨论过 AOP 的基本概念, 需要了解的同学可以参考: 聊聊 AOP 模式与 ObjC 对它的实现 。
Aspects
是一个使用 ObjC 实现的 AOP 第三方库。 我们前面的文章中也介绍了一些 AOP 的实现方式, 一般通过 runtime 的 Method Swizzling 特性来实现这个模式。 Aspects
的底层也是通过 runtime 的这些函数来实现的。不过它对 runtime 函数进行了比较好的封装,使用了最佳实践来调用 runtime 函数。这样免去了我们自己来调用繁杂的 runtime 函数, 避免了我们在不熟悉的情况下写出的不好的实践。
我们来看看使用 Aspects
如何进行 AOP 实践:
[UIViewController aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionAfter usingBlock:^{ NSLog(@"view did appear"); } error:NULL];
上面的代码应该不难理解, 就是对 UIViewController 的 viewDidAppear 方法进行了一个 hook。 注意 AspectPositionAfter 这个参数,它的意思是我们在实际的 viewDidAppear 调用之后,再执行我们传入的 block 中的代码。
这样,我们在运行 APP 后, 所有 UIViewController 的 viewDidAppear 方法被调用的时候,就会执行我们 block 中的 NSLog 输出日志了。
怎么样, Aspects
实现 AOP 是不是非常简单? 只需要一个调用就完成了。
并且 Aspects
在调试的时候还会在 Stack Trace 中生成相关的标记:
这个特性也是非常好用, 尤其是在你 hook 一些你看不到源码的方法的时候。
上面对 Aspects
做了一个简单的介绍,接下来我们可以实际用一个小示例操作一下。 我们首先在 XCode 创建一个项目,然后在项目的跟目录中创建一个文件 Cartfile。 如果不确定根目录是什么,保证 Cartfile 和你的 .xcodeproj 文件同级即可。
Cartfile 是 Carthage 包管理工具的配置文件,我比较偏爱使用 Carthage,当然你也可以使用其他包管理工具,或者不使用包管理,直接下载源码。
这样你的目录结构大概是这样, 比如项目名字叫做 aspects:
在 Cartfile 中, 写入这样的内容:
github "steipete/Aspects"
这样就告诉 Carthage 我们要配置哪些第三方库。 配置好后,运行这个命令:
carthage update
紧接着,你会看到这样的命令输出, Carthage 在下载并且构建 Aspects 库:
构建完成后, 在你的工程文件中会生成一个 Carthage 目录, 这个目录下面的 Build/iOS/Aspects.framework 就是 Carthage 为我们构件好的库了。
最后,将生成的 framewok 拖到 XCode 工程中的 Embedded Binaries 和 Linked Frameworks 中,就完成了这个库的集成:
这样,我们使用 Carthage 完成了 Aspects 库的集成。 关于 Carthage 的基本使用方法,如果你需要了解的话,可以参看这篇文章 Carthage 包管理工具,另一种敏捷轻快的 iOS & MAC 开发体验
集成工作完成后, 我们可以在工程中创建一个类 AOPHelper, 它的代码也很简单:
#import <Aspects/Aspects.h> #import <UIKit/UIKit.h> @interfaceAOPHelper:NSObject + (void) setup; @end @implementationAOPHelper + (void)setup { [UIViewController aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionAfter usingBlock:^{ NSLog(@"view did appear"); } error:NULL]; } @end
它定义了一个 setup 方法, 这个方法中调用 Aspects 的能力对 UIViewController 的 viewDidAppear 方法进行了 hook。 然后在应用启动的时候,我们使用 AOPHelper 来初始化:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [AOPHelper setup]; return YES; }
这样,所有 viewDidAppear 方法被调用之后, 都会执行我们 hook 的内容, 用 NSLog 输出一条信息。
Aspects 对 AOP 模式提供了更好的实践方案, 我们不需要处理 runtime 那些繁琐的函数, 直接使用 Aspects 就可以达成 AOP 模式了。 并且它所提供的 API 逻辑更加直观。 如果你的场景恰好适合 AOP 模式,是否也考虑引入它了呢?
关于 Aspects 的更多内容, 大家看可以参看它的 Github 主页: https://github.com/steipete/Aspects
如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~