Aspects简介:
Aspect是一个基于method swizzing的iOS函数替换的轻量级的第三方库(不足千行代码),有关iOS运行时的相关知识,移步 runtime从入门到精通,他可以很好的实现勾取一个类或者一个对象的某个方法。
面向切面(AOP)编程
面向切面编程就是通过预编译和运行期动态代理实现给程序动态统一添加功能的一种技术,使用Aspects框架就是 AOP 编程。
Aspects框架的对外的两个重要接口声明:
/// Adds a block of code before/instead/after the current `selector` for a specific class.
///
/// @param block Aspects replicates the type signature of the method being hooked.
/// The first parameter will be `id<AspectInfo>`, followed by all parameters of the method.
/// These parameters are optional and will be filled to match the block signature.
/// You can even use an empty block, or one that simple gets `id<AspectInfo>`.
///
/// @note Hooking static methods is not supported.
/// @return A token which allows to later deregister the aspect.
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
/// Adds a block of code before/instead/after the current `selector` for a specific instance.
- (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
以第二个接口为例进行说明:
/**
* 勾取某一对象的某一方法
* selector : 指定对象的方法
* options :枚举类型
* block :执行的自定义方法。在这个block里面添加我们要执行的代码。
**/
- (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
AspectOptions 枚举定义如下,我们一般使用 AspectPositionAfter。AspectPositionAfter 表示 selector 方法执行后会触发block中的代码,AspectPositionBefore 表示方法执行前先触发block中的代码,AspectPositionInstead 表示直接替换原方法。
typedef NS_OPTIONS(NSUInteger, AspectOptions) {
AspectPositionAfter = 0, /// Called after the original implementation (default)
AspectPositionInstead = 1, /// Will replace the original implementation.
AspectPositionBefore = 2, /// Called before the original implementation.
AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
};
Aspects框架的使用
使用场景举例
对用户的页面轨迹进行统计,也即用户每次进入到一个控制器调用 viewWillAppear 函数时进行相应的处理(例如友盟统计)
代码实现
使用cocoapods将Aspects添加到project中。
target 'Project' do
use_frameworks!
pod 'Aspects', '~> 1.4.1'
end
创建一个工具类,导入头文件:
#import <Aspects/Aspects.h>
实现代码:
+ (void)Aspect {
/**
* 事件拦截
* 拦截UIViewController的viewWillAppear方法
*/
[UIViewController aspect_hookSelector:@selector(viewWillAppear) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
//NSLog(@"viewWillAppear调用了 --- %@ --- %@ --- %@",aspectInfo.instance,aspectInfo.arguments, aspectInfo.originalInvocation);
NSLog(@"%@ 对象的viewWillAppear调用了",aspectInfo.instance);
/**
* 添加我们要执行的代码
*/
} error:NULL];
}