CaptainHook 源码分析(七):其他宏接口


CHOptimizedMethod

宏接口 CHOptimizedMethod 用于针对对象方法生成对宏接口 CHMethod_super_CHMethod_self_CHMethod_new_ 的调用,其定义为:

// @param.count  对象方法的参数个数
// @param.args	 可变的参数列表
// 注意:宏接口 CHOptimizedMethod 不能生成对宏接口 CHMethod_ 的调用
#define CHOptimizedMethod(count, args...) \
	CHOptimizedMethod ## count(args)

宏接口 CHOptimizedMethod 会根据传入的对象方法的参数个数
分别生成对宏接口 CHOptimizedMethod0 ~ CHOptimizedMethod9 的调用:

// @param.optimization	如果填 super 则调用 CHMethod_super_ ,如果填 self 则调用 CHMethod_self_ ,如果填 new 则调用 CHMethod_new_
// @param.return_type	对象方法返回值的类型
// @param.class_type	对象方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.name1			对象方法第一部分的方法名称
// @param.type1			对象方法第一个参数的类型
// @param.arg1			对象方法第一个参数的名称
// @param.name2			对象方法第二部分的方法名称
// @param.type2			对象方法第二个参数的类型
// @param.arg2			对象方法第二个参数的名称
// ...
// @param.name9			对象方法第九部分的方法名称
// @param.type9			对象方法第九个参数的类型
// @param.arg9			对象方法第九个参数的名称

// 调用具有 0 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod0(optimization, return_type, class_type, name) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name, name, CHDeclareSig0_(return_type), (self, _cmd))
// 调用具有 1 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod1(optimization, return_type, class_type, name1, type1, arg1) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $, name1:, CHDeclareSig1_(return_type, type1), (self, _cmd, arg1), type1 arg1)
// 调用具有 2 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod2(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $, name1:name2:, CHDeclareSig2_(return_type, type1, type2), (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
// 调用具有 3 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod3(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $, name1:name2:name3:, CHDeclareSig3_(return_type, type1, type2, type3), (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
// 调用具有 4 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod4(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, name1:name2:name3:name4:, CHDeclareSig4_(return_type, type1, type2, type3, type4), (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
// 调用具有 5 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod5(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, name1:name2:name3:name4:name5:, CHDeclareSig5_(return_type, type1, type2, type3, type4, type5), (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
// 调用具有 6 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod6(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, name1:name2:name3:name4:name5:name6:, CHDeclareSig6_(return_type, type1, type2, type3, type4, type5, type6), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)
// 调用具有 7 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod7(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, name1:name2:name3:name4:name5:name6:name7:, CHDeclareSig7_(return_type, type1, type2, type3, type4, type5, type6, type7), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7)
// 调用具有 8 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod8(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, name1:name2:name3:name4:name5:name6:name7:name8:, CHDeclareSig8_(return_type, type1, type2, type3, type4, type5, type6, type7, type8), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8)
// 调用具有 9 个参数的对象方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedMethod9(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8, name9, type9, arg9) \
	CHMethod_ ## optimization ## _(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, name1:name2:name3:name4:name5:name6:name7:name8:name9:, CHDeclareSig9_(return_type, type1, type2, type3, type4, type5, type6, type7, type8, type9), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9)

宏接口 CHOptimizedMethod0 ~ CHOptimizedMethod9 会组织传入的宏参数,生成对宏接口 CHMethod_super_CHMethod_self_CHMethod_new_ 的调用,关于宏接口 CHMethod_super_CHMethod_self_CHMethod_new_ 的详细介绍,请参阅:

CaptainHook 源码分析(三):交换 Objective-C 方法实现的核心代码(使用 RunTime API)
CaptainHook 源码分析(四):交换 Objective-C 方法实现的核心代码(使用 Cydia Substrate)


以调用具有 2 个参数的对象方法 -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]CHMethod_super_ 为例:

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]

CHOptimizedMethod(2, super, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hzp done!!!");
    return nil;
}

CHConstructor
{
    CHLoadLateClass(HcgPerson);
    CHHook(2, HcgPerson, initWithName, age);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]

CHOptimizedMethod2(super, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hzp done!!!");
    return ((void *)0);
}

CHConstructor
{
    CHLoadLateClass(HcgPerson);
    CHHook2(HcgPerson, initWithName, age);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]

CHMethod_super_(HcgPerson*,
                HcgPerson *,
                HcgPerson,
                CHClass(HcgPerson),
                CHSuperClass(HcgPerson),
                initWithName$age$,
                initWithName:age:,
                CHDeclareSig2_(HcgPerson*, NSString*, int),
                (self, _cmd, aName, anAge),
                NSString* aName,
                int anAge)
{
    NSLog(@"hzp done!!!");
    return ((void *)0);
}

CHConstructor
{
    CHLoadLateClass(HcgPerson);
    CHHook_(HcgPerson, initWithName$age$);
}

CHOptimizedClassMethod

宏接口 CHOptimizedClassMethod 用于针对类方法生成对宏接口 CHMethod_super_CHMethod_self_CHMethod_new_ 的调用,其定义为:

// @param.count  类方法的参数个数
// @param.args	 可变的参数列表
// 注意:宏接口 CHOptimizedClassMethod 不能生成对宏接口 CHMethod_ 的调用
#define CHOptimizedClassMethod(count, args...) \
	CHOptimizedClassMethod ## count(args)

宏接口 CHOptimizedClassMethod 会根据传入的类方法的参数个数
分别生成对宏接口 CHOptimizedClassMethod0 ~ CHOptimizedClassMethod9 的调用:

// @param.optimization	如果填 super 则调用 CHMethod_super_ ,如果填 self 则调用 CHMethod_self_ ,如果填 new 则调用 CHMethod_new_
// @param.return_type	类方法返回值的类型
// @param.class_type	类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.name1			类方法第一部分的方法名称
// @param.type1			类方法第一个参数的类型
// @param.arg1			类方法第一个参数的名称
// @param.name2			类方法第二部分的方法名称
// @param.type2			类方法第二个参数的类型
// @param.arg2			类方法第二个参数的名称
// ...
// @param.name9			类方法第九部分的方法名称
// @param.type9			类方法第九个参数的类型
// @param.arg9			类方法第九个参数的名称

// 调用具有 0 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod0(optimization, return_type, class_type, name) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name, name, CHDeclareSig0_(return_type), (self, _cmd))
// 调用具有 1 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod1(optimization, return_type, class_type, name1, type1, arg1) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $, name1:, CHDeclareSig1_(return_type, type1), (self, _cmd, arg1), type1 arg1)
// 调用具有 2 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod2(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $, name1:name2:, CHDeclareSig2_(return_type, type1, type2), (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
// 调用具有 3 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod3(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $, name1:name2:name3:, CHDeclareSig3_(return_type, type1, type2, type3), (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
// 调用具有 4 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod4(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, name1:name2:name3:name4:, CHDeclareSig4_(return_type, type1, type2, type3, type4), (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
// 调用具有 5 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod5(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, name1:name2:name3:name4:name5:, CHDeclareSig5_(return_type, type1, type2, type3, type4, type5), (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
// 调用具有 6 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod6(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, name1:name2:name3:name4:name5:name6:, CHDeclareSig6_(return_type, type1, type2, type3, type4, type5, type6), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)
// 调用具有 7 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod7(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, name1:name2:name3:name4:name5:name6:name7:, CHDeclareSig7_(return_type, type1, type2, type3, type4, type5, type6, type7), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7)
// 调用具有 8 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod8(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, name1:name2:name3:name4:name5:name6:name7:name8:, CHDeclareSig8_(return_type, type1, type2, type3, type4, type5, type6, type7, type8), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8)
// 调用具有 9 个参数的类方法的(CHMethod_super_ 或者 CHMethod_self_ 或者 CHMethod_new_)
#define CHOptimizedClassMethod9(optimization, return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8, name9, type9, arg9) \
	CHMethod_ ## optimization ## _(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, name1:name2:name3:name4:name5:name6:name7:name8:name9:, CHDeclareSig9_(return_type, type1, type2, type3, type4, type5, type6, type7, type8, type9), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9)

宏接口 CHOptimizedClassMethod0 ~ CHOptimizedClassMethod9 会组织传入的宏参数,生成对宏接口 CHMethod_super_CHMethod_self_CHMethod_new_ 的调用,关于宏接口 CHMethod_super_CHMethod_self_CHMethod_new_ 的详细介绍,请参阅:

CaptainHook 源码分析(三):交换 Objective-C 方法实现的核心代码(使用 RunTime API)
CaptainHook 源码分析(四):交换 Objective-C 方法实现的核心代码(使用 Cydia Substrate)


以调用具有 2 个参数的类方法 +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]CHMethod_super_ 为例:

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]

CHOptimizedClassMethod(2, super, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hcg done!!!");
    return nil;
}

CHConstructor
{
    CHLoadLateClass(HcgPerson);
    CHClassHook(2, HcgPerson, personWithName, age);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]

CHOptimizedClassMethod2(super, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hcg done!!!");
    return ((void *)0);
}

CHConstructor
{
    CHLoadLateClass(HcgPerson);
    CHClassHook2(HcgPerson, personWithName, age);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]

CHMethod_super_(HcgPerson*,
                id,
                HcgPerson,
                CHMetaClass(HcgPerson),
                object_getClass(CHMetaClass(HcgPerson)),
                personWithName$age$,
                personWithName:age:,
                CHDeclareSig2_(HcgPerson*, NSString*, int),
                (self, _cmd, aName, anAge),
                NSString* aName,
                int anAge)
{
    NSLog(@"hcg done!!!");
    return ((void *)0);
}

CHConstructor
{
    CHLoadLateClass(HcgPerson);
    CHHook_(HcgPerson, personWithName$age$);
}

用于调试和日志的相关宏接口

  • 宏定义 CHAppName 用于标识当前 App 的名称,如果开发者没有显式定义,则其默认值为 "CaptainHook"

    #ifndef CHAppName
    #define CHAppName "CaptainHook"
    #endif
    
  • 如果使用 Clang 编译器并且开启了 ARC 模式,则定义宏 CHHasARC

    #ifdef __clang__
    #if __has_feature(objc_arc)
    #define CHHasARC
    #endif
    #endif
    
  • 宏接口 CHStringify(x) 用于将标记 x 转换为字符串,其定义为:

    #define CHStringify_(x) #x
    #define CHStringify(x) CHStringify_(x)
    

    使用示例:

    #import "CaptainHook.h"
    
    CHConstructor
    {
        const char * name0 = CHStringify(hcg);
        NSLog(@"name0 = %s", name0); // 输出结果为 name0 = hcg
        
        NSString* name1 = @CHStringify(hzp);
        NSLog(@"name1 = %@", name1); // 输出结果为 name1 = hzp
    }
    
  • 宏接口 CHConcat(a, b) 用于将语言符号 a 和语言符号 b 组成一个语言符号 ab,其定义为:

    #define CHConcat_(a, b) a ## b
    #define CHConcat(a, b) CHConcat_(a, b)
    

    使用示例:

    #import "CaptainHook.h"
    
    int hcg_sum(int num1, int num2)
    {
        return num1 + num2;
    }
    
    CHConstructor
    {
        int result0 = CHConcat(hcg_, sum)(10, 20);
        NSLog(@"result0 = %d", result0); // 输出结果为 result0 = 30
        
        int result1 = CHConcat(hcg, _sum)(10, 20);
        NSLog(@"result1 = %d", result1); // 输出结果为 result1 = 30
    }
    
  • 宏接口 CHNothing() 的本质是一个只执行一次的空的 do-while 循环,正如其名称所述,调用宏接口 CHNothing() 将不执行任何操作

    #define CHNothing() do { } while(0)
    
  • 宏接口 CHLocationInSource 用于生成(包含其所在行号和所属函数的)字符串,其定义为:

    #define CHLocationInSource [NSString stringWithFormat:@CHStringify(__LINE__) " in %s", __FUNCTION__]
    

    使用示例:

    #import "CaptainHook.h"
    
    CHConstructor
    {
        NSString* desc = CHLocationInSource;
        NSLog(desc);                // 输出结果为 8 in CHConstructor6
        NSLog(CHLocationInSource);  // 输出结果为 10 in CHConstructor6
    }
    
  • 宏接口 CHLog(args...) 用于输出日志信息(日志信息中包含:App 名称、所传入的参数列表),其定义为:

    #define CHLog(args...)			NSLog(@CHAppName ": %@", [NSString stringWithFormat:args])
    

    使用示例:

    #import <Foundation/Foundation.h>
    #import "CaptainHook.h"
    
    CHConstructor
    {
        NSString* name = @"hcg";
        int age = 20;
        CHLog(@"name = %@, age = %d", name, age); 
        // 输出结果为 
        // CaptainHook: name = hcg, age = 20
    }
    
  • 宏接口 CHLogSource(args...) 用于输出日志信息(日志信息中包含:App 名称、所在行号、所属函数、所传入的参数列表),其定义为:

    #define CHLogSource(args...)	NSLog(@CHAppName " @ " CHStringify(__LINE__) " in %s: %@", __FUNCTION__, [NSString stringWithFormat:args])
    

    使用示例:

    #import <Foundation/Foundation.h>
    #import "CaptainHook.h"
    
    int hcg_sum(int num1, int num2)
    {
        return num1 + num2;
    }
    
    CHConstructor
    {
        NSString* name = @"hcg";
        int age = 20;
        CHLogSource(@"name = %@, age = %d", name, age); // 输出结果为 CaptainHook @ 13 in CHConstructor9: name = hcg, age = 20
    }
    
  • 在 Debug 模式下:
    宏接口 CHDebugLog(args...) 会生成对宏接口 CHLog(args...) 的调用
    宏接口 CHDebugLogSource(args...) 会生成对宏接口 CHLogSource(args...) 的调用
    在 Release 模式下:
    调用宏接口 CHDebugLog(args...)CHDebugLogSource(args...) 会生成对宏接口 CHNothing() 的调用,即不执行任何操作

    #ifdef CHDebug
    #define CHDebugLog(args...)			CHLog(args)
    #define CHDebugLogSource(args...)	CHLogSource(args)
    #else
    #define CHDebugLog(args...)			CHNothing()
    #define CHDebugLogSource(args...)	CHNothing()
    #endif
    

其他宏接口

  • MRC 模式下的自动释放池(CHAutoreleasePoolForScope)

    宏接口 CHAutoreleasePoolForScope() 用于在其作用域内初始化一个自动释放池,其定义为:

    #define CHScopeReleased \
    	__attribute__((cleanup(CHScopeReleased)))
    
    #define CHAutoreleasePoolForScope() \
    	NSAutoreleasePool *CHAutoreleasePoolForScope __attribute__((unused)) CHScopeReleased = [[NSAutoreleasePool alloc] init]
    #endif
    

    __attribute__((unused)) 用于告诉编译器:当被修饰的函数或者变量没有被使用时,不要报警告

    __attribute__((cleanup(CHScopeReleased))) 用于告诉编译器:如果声明的变量离开了其作用域,则自动调用销毁函数 CHScopeReleased(并将该变量作为参数传递给销毁函数)。销毁函数 CHScopeReleased 的定义为:

    __attribute__((unused)) CHInline
    static void CHScopeReleased(id* sro)
    {
    	[*sro release] ;
    }
    

    使用示例:

    // 需要为目标源文件添加编译标识:Target - Build Phases - Compile Sources - 目标源文件 - fno-objc-arc
    #import <Foundation/Foundation.h>
    #import "CaptainHook.h"
    
    CHConstructor
    {
        CHAutoreleasePoolForScope();
        
        NSObject* obj0 = [[[NSObject alloc] init] autorelease];
        NSObject* obj1 = [[[NSObject alloc] init] autorelease];
        
        // CHAutoreleasePoolForScope(); 的作用域结束后,会自动释放 obj0 和 obj1 
    }
    
  • 编译阶段的断言(CHBuildAssert)

    宏接口 CHBuildAssert(condition) 用于在编译阶段断言条件 condition 是否满足。如果条件 condition 满足,则会在编译阶段提示错误,而不是等到运行阶段再出现奔溃。宏接口 CHBuildAssert(condition) 的定义为:

    // 如果条件 condition 满足,则结果为 ((void)sizeof(char[-1])),编译失败
    // 如果条件 condition 不满足,则结果为 ((void)sizeof(char[1])),编译成功
    #define CHBuildAssert(condition) \
    	((void)sizeof(char[1 - 2*!!(condition)]))
    

    使用示例:

    #import "CaptainHook.h"
    
    CHConstructor
    {
        // 以下 3 行代码将编译成功
        CHBuildAssert(NO);
        CHBuildAssert(false);
        CHBuildAssert(0);
        
        // 以下 3 行代码将编译失败。报错: Array size is negative
        CHBuildAssert(YES);
        CHBuildAssert(true);
        CHBuildAssert(1);
    }
    
  • 代码块的耗时统计(CHProfileScope)

    宏接口 CHProfileScope() 用于在其作用域内初始化一个计时器(以统计其作用域内所包含的代码块的耗时),其定义为:

    #define CHProfileScope() \
    	CHProfileScopeWithFormat(@CHStringify(__LINE__) " in %s", __FUNCTION__)
    

    宏接口 CHProfileScope() 会根据其所在行号和所属函数,生成对宏接口 CHProfileScopeWithFormat 的调用

    #define CHProfileScopeWithFormat(args...) \
    	CHProfileScopeWithString(([NSString stringWithFormat:args]))
    

    宏接口 CHProfileScopeWithFormat 会组织传入的参数,生成对宏接口 CHProfileScopeWithString 的调用

    #define CHProfileScopeWithString(string) \
    		struct CHProfileData _profileData __attribute__((cleanup(CHProfileCalculateDurationAndLog_))) = ({ struct CHProfileData _tmp; _tmp.message = (string); _tmp.startTime = mach_absolute_time(); _tmp; })
    

    宏接口 CHProfileScopeWithString 会初始化一个 struct CHProfileData 结构体类型的变量 _profileData
    其中 __attribute__((cleanup(CHProfileCalculateDurationAndLog_))) 用于告诉编译器:如果声明的变量 _profileData 离开了其作用域,则自动调用销毁函数 CHProfileCalculateDurationAndLog_

    结构体 struct CHProfileData 和销毁函数 CHProfileCalculateDurationAndLog_ 的定义为:

    #import <mach/mach_time.h>
    
    struct CHProfileData
    {
    	NSString* message;
    	uint64_t startTime;
    };
    
    __attribute__((unused)) CHInline
    static void CHProfileCalculateDurationAndLog_(struct CHProfileData* profileData)
    {
    	uint64_t duration = mach_absolute_time() - profileData->startTime;
    	mach_timebase_info_data_t info;
    	mach_timebase_info(&info);
    	duration = (duration * info.numer) / info.denom;
    	CHLog(@"Profile time: %lldns; %@", duration, profileData->message);
    }
    

    如下代码:

    #import <Foundation/Foundation.h>
    
    #define CHEnableProfiling
    #import "CaptainHook.h"
    
    CHConstructor
    {
        CHProfileScope();
        
        for (int i = 0; i < 1000; i++) {
            NSLog(@"times = %d", i);
        }
    	
    	// 用于统计 for 循环的执行时间(单位:纳秒)
    }
    

    等价于

    #import <Foundation/Foundation.h>
    
    #define CHEnableProfiling 1
    #import "CaptainHook.h"
    
    CHConstructor
    {
        CHProfileScopeWithFormat(@CHStringify(8) " in %s", __FUNCTION__);
    	
    	for (int i = 0; i < 1000; i++) {
    		NSLog(@"times = %d", i);
    	}
    }
    

    等价于

    #import <Foundation/Foundation.h>
    
    #define CHEnableProfiling
    #import "CaptainHook.h"
    
    CHConstructor
    {
        CHProfileScopeWithString(([NSString stringWithFormat:@CHStringify(8) " in %s", __FUNCTION__]));
        
    	for (int i = 0; i < 1000; i++) {
    		NSLog(@"times = %d", i);
    	}
    }
    

    预处理后的结果为:

    ...
    
    #pragma clang module import Darwin.Mach.mach_time /* clang -E: implicit import for #import <mach/mach_time.h> */
    
    struct CHProfileData
    {
        NSString *message;
        uint64_t startTime;
    };
    
    __attribute__((unused)) inline __attribute__((always_inline))
    static void CHProfileCalculateDurationAndLog_(struct CHProfileData *profileData)
    {
        uint64_t duration = mach_absolute_time() - profileData->startTime;
        mach_timebase_info_data_t info;
        mach_timebase_info(&info);
        duration = (duration * info.numer) / info.denom;
        NSLog(@"CaptainHook" ": %@", [NSString stringWithFormat:@"Profile time: %lldns; %@", duration, profileData->message]);
    }
    
    static __attribute__((constructor)) void CHConstructor6()
    {
        struct CHProfileData _profileData __attribute__((cleanup(CHProfileCalculateDurationAndLog_))) =
        ({
            struct CHProfileData _tmp;
            _tmp.message = (([NSString stringWithFormat:@"8" " in %s", __FUNCTION__]));
            _tmp.startTime = mach_absolute_time();
            _tmp;
        });
    	
    	for (int i = 0; i < 1000; i++) {
    		NSLog(@"times = %d", i);
    	}
    }
    
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值