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