Aspects - 也许是你正需要的 AOP 实现

swift 发布于 2017年09月23日
AOP 模式

AOP 是一种帮助你将代码逻辑变得更清晰的设计模式, 咱们前面的文章中讨论过 AOP 的基本概念, 需要了解的同学可以参考: 聊聊 AOP 模式与 ObjC 对它的实现

Aspects

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>


@interface AOPHelper : NSObject

+ (void) setup;

@end



@implementation AOPHelper

+ (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,会有更多我的原创内容分享给你~

本站文章均为原创内容,如需转载请注明出处,谢谢。
关注微信公众号
发现更多精彩
swift-cafe