文章

方法替换

Aspects

Aspects 是一个基于 Method Swizzle 的函数替换的第三方库,支持在方法执行前(AspectPositionBefore)/执行后(AspectPositionAfter)或替代原方法执行(AspectPositionInstead)

使用

  1. HOOK一个类的所有实例的指定方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    /// 为一个指定的类的某个方法执行前/替换/后,添加一段代码块.对这个类的所有对象都会起作用.
    ///
    /// @param block  方法被添加钩子时,Aspectes会拷贝方法的签名信息.
    /// 第一个参数将会是 `id<AspectInfo>`,余下的参数是此被调用的方法的参数.
    /// 这些参数是可选的,并将被用于传递给block代码块对应位置的参数.
    /// 你甚至使用一个没有任何参数或只有一个`id<AspectInfo>`参数的block代码块.
    ///
    /// @注意 不支持给静态方法添加钩子.
    /// @return 返回一个唯一值,用于取消此钩子.
    + (id<AspectToken>)aspect_hookSelector:(SEL)selector
                       withOptions:(AspectOptions)options
                        usingBlock:(id)block
                             error:(NSError **)error;
    
  2. HOOK一个类实例的指定方法
    1
    2
    3
    4
    5
    
    /// 为一个指定的对象的某个方法执行前/替换/后,添加一段代码块.只作用于当前对象.
    - (id<AspectToken>)aspect_hookSelector:(SEL)selector
                       withOptions:(AspectOptions)options
                        usingBlock:(id)block
                             error:(NSError **)error;
    
  3. Example
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    +(void)Aspect {
     // 在类UIViewController所有的实例执行viewWillAppear:方法完毕后做一些事情
     [UIViewController aspect_hookSelector:@selector(viewWillAppear:)
                               withOptions:AspectPositionAfter
                                usingBlock:^(id<AspectInfo> info) {
                                    NSString *className = NSStringFromClass([[info instance] class]);
                                    NSLog(@"%@", className);
                                } error:NULL];
    
     // 在实例myVc执行viewWillAppear:方法完毕后做一些事情
     UIViewController* myVc = [[UIViewController alloc] init];
     [myVc aspect_hookSelector:@selector(viewWillAppear:)
                             withOptions:AspectPositionAfter
                              usingBlock:^(id<AspectInfo> info) {
                                  id instance = info.instance;               //调用的实例对象
                                  id invocation = info.originalInvocation;   //原始的方法
                                  id arguments = info.arguments;             //参数
                                  [invocation invoke];                       //原始的方法,再次调用
                              } error:NULL];
     // HOOK类方法
     Class metalClass = objc_getMetaClass(NSStringFromClass(UIViewController.class).UTF8String);
     [metalClass aspect_hookSelector:@selector(ClassMethod)
                         withOptions:AspectPositionAfter
                          usingBlock:^(id<AspectInfo> info) {
                              NSLog(@"%@", HOOK类方法);
                          } error:NULL];
    }
    
本文由作者按照 CC BY 4.0 进行授权