关于 Aspect
在项目中我们经常会广泛使用继承设计模式,例如统一功能的基类BaseModel
、BaseView
、BaseService
,当不复杂的基类用起来还好,当基类的功能种类繁多的时候,通常会造成基类臃肿难以维护,增加额外的学习成本。
使用切面编程的初衷是我们需要一个职责清晰的基类
Aspect
是一款让人用起来愉快的切面编程库,底层是method Swizzling
。它允许您为每个类或每个实例的现有方法添加代码,同时考虑插入点,例如在/之前/之后。“Aspect
是稳定的,并在数百个应用中使用”——这是选择Aspect
最重要的理由。
使用 Aspect + category代替继承
category
秉承“为现有类添加功能”的原则,category
极大方便了我们对一些类的扩展,是解耦的首选设计模式。
我们采用category
+ Aspect
的方式来分割,每个功能都有自己的一个category
。以UIViewController
为例:
UIViewController + Navigation
UIViewController + UserEvent
UIViewController + LogReport
每个类别都在 +(void)load
里面声明一下即可在相应的方法里添加函数
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo>aspectInfo){
[self viewDidLoad:[aspectInfo instance]];
} error:nil];
[self aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo>aspectInfo){
[self viewWillAppear:[aspectInfo instance]];
} error:nil];
[self aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo>aspectInfo){
[self viewDidLoad:[aspectInfo instance]];
} error:nil];
});
}
+ (void)viewDidLoad:(UIViewController *)viewController{
NSLog(@"[%@ viewDidLoad]", [viewController class]);
}
+ (void)viewWillAppear:(UIViewController *)viewController{
NSLog(@"[%@ viewWillAppear]",[viewController class]);
}
+ (void)viewWillDisappear:(UIViewController *)viewController{
NSLog(@"[%@ viewWillDisappear]",[viewController class]);
}
将Aspect
注册放在+(void)load
中,在main
函数之前就会运行,所以不需要import
。
Tips:关于category
很多小伙伴没有真正理解category
的用法,把很多函数都用category来设计。例如之前我见到一个NSString+Path
的类别,实现的功能大概是这些
/// eg: documents/12314
+ (NSString *)userFolder;
/// eg:documents/12314/UserInfo
+ (NSString *)userInfoFolder;
/// eg:documents/12314/broon_12314.sqlite
+ (NSString *)databasePath;
/// eg:documents/12314/UserInfo/broon_userInfo.sqlite
+ (NSString *)userInfoDatabasePath;
/// eg:12314
+ (NSString *)userID;
项目配置类的基本上没用到NSString
里的功能,所以类似这种情况下的还是老老实实写个NSObject
类或者实体类来代替。
我的组件化系列文章:
《iOS组件化》组件化实践
《iOS组件化》组件的划分
《iOS组件化》创建公共/私有 Pods
《iOS组件化》之 搭建适合业务的URL跳转路由-ALRouter
《iOS组件化》之搭建基于AFNetworking的网络请求框架