《iOS组件化》之使用AOP代替继承

关于 Aspect

在项目中我们经常会广泛使用继承设计模式,例如统一功能的基类BaseModelBaseViewBaseService,当不复杂的基类用起来还好,当基类的功能种类繁多的时候,通常会造成基类臃肿难以维护,增加额外的学习成本。

《iOS组件化》之使用AOP代替继承_第1张图片
base.png

使用切面编程的初衷是我们需要一个职责清晰的基类
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:^(idaspectInfo){
            [self viewDidLoad:[aspectInfo instance]];
        } error:nil];
        [self aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionBefore usingBlock:^(idaspectInfo){
            [self viewWillAppear:[aspectInfo instance]];
        } error:nil];
        [self aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionBefore usingBlock:^(idaspectInfo){
            [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的网络请求框架

你可能感兴趣的:(《iOS组件化》之使用AOP代替继承)