美文网首页
Aspects源码详解(一)

Aspects源码详解(一)

作者: Jimm_鱼 | 来源:发表于2018-10-21 19:06 被阅读6次

AOP(Aspect Oriented Programming)面向切片编程

  • AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

iOS 如何如何实现面向切片编程

  • AOP一般都是需要有一个拦截器,然后在每一个切片运行之前和运行之后(或者任何你希望的地方),通过调用拦截器的方法来把这个jointpoint扔到外面,在外面获得这个jointpoint的时候,执行相应的代码。
  • 在iOS开发领域,objective-C的runtime有提供了一系列的方法,能够让我们拦截到某个方法的调用,来实现拦截器的功能,这种手段我们称为Method Swizzling。Aspects通过这个手段实现了针对某个类和某个实例中方法的拦截。

使用场景:

  • 统一处理逻辑
  • 在不改变源码的情况下,插入源码
  • 当我们执行某种方法时候,对方法进行安全检查 (例如,NSArray的数组越界问题)
  • 对某些操作进行日志记录
  • 对购物车进行交互时候,根据用户的操作,触发建议或者提示

源码解析:

AspectOptions

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.
};

这是一个枚举,定义了切片的调用时机

公共接口

#pragma mark - Public Aspects API
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
                      withOptions:(AspectOptions)options
                       usingBlock:(id)block
                            error:(NSError **)error {
    return aspect_add((id)self, selector, options, block, error);
}

/// @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 {
    return aspect_add(self, selector, options, block, error);
}

Aspects是NSObject的分类 @interface NSObject (Aspects),然后提供了实例方法和类方法

  • 参数
    1. selector: 要被hook的selector,这是一个SEL类型
    2. options: 切面的执行时机,也就是设置第三个参数block的调用时
    3. block: 切面 (block 是带有自动变量值的匿名函数,其实block的实质也是Objective-C的对象,所以这里能用id来引用,具体详细解析可以参考《Objective-C高级编程》这一本书)
    4. error: hook过程中出现的错误

aspect_add

static id aspect_add(id self, SEL selector, AspectOptions options, id block, NSError **error) {
    NSCParameterAssert(self);
    NSCParameterAssert(selector);
    NSCParameterAssert(block);

    __block AspectIdentifier *identifier = nil;
    aspect_performLocked(^{
        if (aspect_isSelectorAllowedAndTrack(self, selector, options, error)) {
            AspectsContainer *aspectContainer = aspect_getContainerForObject(self, selector);
            identifier = [AspectIdentifier identifierWithSelector:selector object:self options:options block:block error:error];
            if (identifier) {
                [aspectContainer addAspect:identifier withOptions:options];

                // Modify the class to allow message interception.
                aspect_prepareClassAndHookSelector(self, selector, error);
            }
        }
    });
    return identifier;
}

static void aspect_performLocked(dispatch_block_t block) {
    static OSSpinLock aspect_lock = OS_SPINLOCK_INIT;
    OSSpinLockLock(&aspect_lock);
    block();
    OSSpinLockUnlock(&aspect_lock);
}

下个系列的文章后面待续

相关文章

网友评论

      本文标题:Aspects源码详解(一)

      本文链接:https://www.haomeiwen.com/subject/qqfizftx.html