XAspect 是一个 Objective-C 框架,用于实现面向切面编程,使代码更易于 复用 和 维护。
它提供了宏和 API,可以将您的切面实现绑定到目标 Objective-C 方法,不管您是否有源代码实现,甚至可以将 Apple 的 SDK 绑定!
XAspect 将切面逻辑(或 横切关注点)从您的项目中分离出来,并封装到独立的切面文件中。一旦程序加载完成,XAspect 将通过 方法交换 自动将这些补丁合并到您的程序中。
如果您已经了解了 XAspect,可以跳过下面的部分,直接跳转到 目录(“更多信息”部分”)。
您也可以简单地将 XAspect 硬件加入到您的项目中。只需将 XAspect/
目录下的所有源文件和文件夹添加到您的项目中。
使用 XAspect 的感觉就像是为源代码编写 补丁 或 插件。通过几行代码创建一个切面上下文,您就可以开始编写补丁实现了。XAspect 将在程序加载完成后自动将这些补丁合并到您的程序中。
例如,假设您想要在每次对象初始化时记录一个消息,您需要观察 -[NSObject init]
的调用。通过 XAspect,您可以轻松地向 -[NSObject init]
添加 NSLog()
语句。
您可以通过以下方式亲自尝试:
在仓库中的 XAspectDev 项目中找到 Aspect-ObjectAllocation.m 样本代码,并取消注释 AspectPatch()
中的实现,或者
在您的项目中创建一个 Aspect-ObjectAllocation.m,并添加以下代码(您也应注意安装 XAspect)
// In an aspect file you create (.m file).
#import <Foundation/Foundation.h>
#import <XAspect/XAspect.h>
// A aspect namespace for the aspect implementation field (mandatory).
#define AtAspect ObjectLifetime
// Create an aspect patch field for the class you want to add the aspect patches to.
#define AtAspectOfClass NSObject
@classPatchField(NSObject)
// Intercept the target objc message.
AspectPatch(-, instancetype, init)
{
// Add your custom implementation here.
NSLog(@"[Init]: %@", NSStringFromClass([self class]));
// Forward the message to the source implementation.
return XAMessageForward(init);
}
@end
#undef AtAspectOfClass
#undef AtAspect
运行程序。程序加载完成后,您将看到任何对象初始化时的消息
[Init]: NSUserDefaults
[Init]: NSProcessInfo
[Init]: CFPrefsSource
...
您也可以向 -dealloc
添加 前置建议 来打印特定类释放的对象。
#import <XAspect/XAspect.h>
#import <UIKit/UIKit.h>
// -----------------------------------------------------------------------------
#define AtAspect DeallocTracker
// -----------------------------------------------------------------------------
#define AtAspectOfClass NSObject
@classPatchField(NSObject)
AspectPatch(-, void, dealloc)
{
static NSArray *klasses;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Add classes here which you want to track when they were deallocated.
klasses = @[[UITableView class],
[UITableViewController class],
];
});
Class klass = [self class];
if ([klasses containsObject:klass]) {
NSLog(@"--%@ <%p> dealloc", NSStringFromClass(klass), self);
}
XAMessageForwardDirectly(dealloc);
}
@end
#undef AtAspectOfClass
XAspect 旨在将切面代码与源代码实现分离,并在程序加载时重新注入。
使用 XAspect 有一些好处:
有一些缺点和限制。请在文档部分“缺点和限制”中阅读‘缺点和限制’。
任何帮助或贡献都欢迎使用。请阅读开发笔记以找到您可以帮忙的内容。
XAspect 可在 MIT 许可下使用。有关更多信息,请参阅LICENSE 文件。