目录
计算方法的类型编码(CHDeclareSig0_ ~ CHDeclareSig9_)
在 CaptainHook.h
中,宏接口 CHDeclareSig0_
~ CHDeclareSig9_
用于根据方法的返回值类型和参数类型,生成方法的类型编码(其中数字 0~9
用于标识方法的参数个数 )。生成的方法类型编码保存在字符数组 char sig[]
中。以(为具有 1 个返回值,2 个参数的 Objective-C 方法生成方法类型编码的)宏接口 CHDeclareSig2_
为例。宏接口 CHDeclareSig2_
的定义为:
// @param.return_type 返回值的类型
// @param.type1 第一个参数的类型
// @param.type2 第二个参数的类型
#define CHDeclareSig2_(return_type, type1, type2) \
const char *return_ = @encode(return_type); \
size_t return_len = __builtin_strlen(return_); \
const char *type1_ = @encode(type1); \
size_t type1_len = __builtin_strlen(type1_); \
const char *type2_ = @encode(type2); \
size_t type2_len = __builtin_strlen(type2_); \
char sig[return_len+2+type1_len+type2_len+1]; \
__builtin_memcpy(sig, return_, return_len); \
sig[return_len] = _C_ID; \
sig[return_len+1] = _C_SEL; \
__builtin_memcpy(&sig[return_len+2], type1_, type1_len); \
__builtin_memcpy(&sig[return_len+2+type1_len], type2_, type2_len); \
sig[return_len+type1_len+type2_len+2] = '\0';
如下代码:
#import "CaptainHook.h"
CHDeclareClass(HcgPerson)
CHConstructor
{
// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge];
CHDeclareSig2_(HcgPerson*, // @param.return_type 返回值的类型
NSString*, // @param.type1 第一个参数的类型
int) // @param.type2 第二个参数的类型
NSLog(@"sig = %s", sig);
// 输出结果:
// sig = @@:@i
}
预处理后的结果为:
... ...
@class HcgPerson;
static CHClassDeclaration_ HcgPerson$;
static __attribute__((constructor)) void CHConstructor5()
{
// 计算返回值的类型编码与长度
const char *return_ = @encode(HcgPerson*);
size_t return_len = __builtin_strlen(return_);
// 计算参数 1 的类型编码与长度
const char *type1_ = @encode(NSString*);
size_t type1_len = __builtin_strlen(type1_);
// 计算参数 2 的类型编码与长度
const char *type2_ = @encode(int);
size_t type2_len = __builtin_strlen(type2_);
// 根据(返回值类型编码的长度 + 2 + 所有参数类型编码的总长度 + 1)定义一个字符数组 char sig[]
// 为什么字符数组的长度要 +2 ?因为字符数组中要放置隐式形参 id self 和 SEL _cmd 的类型编码
// 为什么字符数组的长度要 +1 ?因为在 C 语言中,一次字符数组的读取以 '\0' 作为结束
char sig[return_len+2+type1_len+type2_len+1];
// 将返回值的类型编码拷贝到字符数组 sig 中
__builtin_memcpy(sig, return_, return_len);
// 将隐式形参 id self 的类型编码添加到字符数组 sig 中
sig[return_len] = '@';
// 将隐式形参 SEL _cmd 的类型编码添加到字符数组 sig 中
sig[return_len+1] = ':';
// 将参数 1 的类型编码拷贝到字符数组 sig 中
__builtin_memcpy(&sig[return_len+2], type1_, type1_len);
// 将参数 2 的类型编码拷贝到字符数组 sig 中
__builtin_memcpy(&sig[return_len+2+type1_len], type2_, type2_len);
// 在字符数组的末尾添加 '\0' 作为结束符
sig[return_len+type1_len+type2_len+2] = '\0';
NSLog(@"sig = %s", sig);
// 输出结果:
// sig = @@:@i
}
生成交换 Objective-C 方法实现的核心代码(CHMethod_)
在 CaptainHook.h
中,宏接口 CHMethod_
用于生成(交换 Objective-C 方法实现的核心代码),其定义为:
// @param.return_type 方法返回值的类型
// @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
// @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
// @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
// @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
// @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
// @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
// @param.supercall 调用闭包函数 xxx_closure 的参数列表
// @param.args... 方法的形参列表
#define CHMethod_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, args...) \
static return_type (*$ ## class_name ## _ ## name ## _super)(class_type self, SEL _cmd, ##args); \
static return_type $ ## class_name ## _ ## name ## _closure(class_type self, SEL _cmd, ##args) { \
typedef return_type (*supType)(class_type, SEL, ## args); \
supType supFn = (supType)class_getMethodImplementation(super_class_val, _cmd); \
return supFn supercall; \
} \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args); \
__attribute__((always_inline)) \
static inline void $ ## class_name ## _ ## name ## _register() { \
Method method = class_getInstanceMethod(class_val, @selector(sel)); \
if (method) { \
$ ## class_name ## _ ## name ## _super = (__typeof__($ ## class_name ## _ ## name ## _super))method_getImplementation(method); \
if (class_addMethod(class_val, @selector(sel), (IMP)&$ ## class_name ## _ ## name ## _method, method_getTypeEncoding(method))) { \
$ ## class_name ## _ ## name ## _super = &$ ## class_name ## _ ## name ## _closure; \
} else { \
method_setImplementation(method, (IMP)&$ ## class_name ## _ ## name ## _method); \
} \
} else { \
sigdef; \
class_addMethod(class_val, @selector(sel), (IMP)&$ ## class_name ## _ ## name ## _method, sig); \
} \
} \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args)
该宏接口做了四件事(以 Hook -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
为例):
-
定义了一个用于保存方法原始实现的函数指针(方法的原始实现,可能存储在当前类中,也可能存储在当前类的父类中)(供宏接口
CHSuper_
调用)static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
-
定义了一个用于调用方法原始实现的闭包函数(在此情景下,方法的原始实现存储在当前类的父类中)
static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
-
方法的替换实现的函数声明 + 方法的替换实现的函数实现
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
-
定义了一个用于(交换方法原始实现与方法替换实现)的注册函数(供宏接口
CHHook_
调用)__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register() { ... }
如下代码:
#import "HcgPerson.h"
#import "CaptainHook.h"
CHDeclareClass(HcgPerson)
// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHMethod_(HcgPerson*, // @param.return_type 方法返回值的类型
HcgPerson*, // @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
HcgPerson, // @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
CHClass(HcgPerson), // @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
CHSuperClass(HcgPerson), // @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
initWithName$age$, // @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
initWithName:age:, // @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
CHDeclareSig2_(HcgPerson*, NSString*, int), // @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
(self, _cmd, aName, anAge), // @param.supercall 调用闭包函数 xxx_closure 的参数列表
NSString* aName, // @param.args... 方法的形参列表
int anAge)
{
NSLog(@"CHMethod_ : hzp done!!!");
return nil;
}
CHConstructor
{
CHLoadLateClass(HcgPerson);
CHHook(2, HcgPerson, initWithName, age);
}
预处理后的结果为:
#pragma clang module import Foundation /* clang -E: implicit import for #import <Foundation/Foundation.h> */
#pragma clang assume_nonnull begin
@interface HcgPerson : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) int age;
-(instancetype)initWithName:(NSString *)aName age:(int)anAge;
+(instancetype)personWithName:(NSString *)aName age:(int)anAge;
-(NSString *)eatFood:(NSString *)aFood inPlace:(NSString *)aPlace;
+(int)doAdditionWithNum1:(int)num1 num2:(int)num2;
+(instancetype)sharedInstance;
@end
#pragma clang assume_nonnull end
#pragma clang module import ObjectiveC.runtime /* clang -E: implicit import for #import <objc/runtime.h> */
#pragma clang module import ObjectiveC.message /* clang -E: implicit import for #import <objc/message.h> */
#pragma clang module import Foundation.NSObject /* clang -E: implicit import for #import <Foundation/NSObject.h> */
#pragma clang module import Foundation.NSObjCRuntime /* clang -E: implicit import for #import <Foundation/NSObjCRuntime.h> */
struct CHClassDeclaration_
{
Class class_;
Class metaClass_;
Class superClass_;
};
typedef struct CHClassDeclaration_ CHClassDeclaration_;
static inline Class CHLoadClass_(CHClassDeclaration_* declaration, Class value)
{
declaration->class_ = value;
declaration->metaClass_ = object_getClass(value);
declaration->superClass_ = class_getSuperclass(value);
return value;
}
__attribute__((unused)) inline __attribute__((always_inline))
static void* CHIvar_(id object, const char * name)
{
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (ivar)
return (void *)&((char *)(__bridge void *)object)[ivar_getOffset(ivar)];
return ((void*)0);
}
@class HcgPerson;
static CHClassDeclaration_ HcgPerson$;
// 供宏接口 CHSuper_ 调用的函数指针,用于指向 -[HcgPerson initWithName:age:] 方法的原始实现
// 1.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的类对象中
// 则该函数指针指向 HcgPerson 的类对象中的 -initWithName:age: 方法实现
// 2.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的父类对象中
// 则该函数指针指向闭包函数 $HcgPerson_initWithName$age$_closure
// 而闭包函数 $HcgPerson_initWithName$age$_closure 会负责调用 HcgPerson 的父类对象中的 -initWithName:age: 方法实现
static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
// 用于调用存储在 HcgPerson 的父类对象中的 -initWithName:age: 方法的原始实现的闭包函数
static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
{
// 定义函数指针类型:supType
// supType 用于定义指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
typedef HcgPerson* (*supType)(HcgPerson*, SEL, NSString* aName, int anAge);
// 从 HcgPerson 的父类对象中,获取指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
supType supFn = (supType)class_getMethodImplementation(HcgPerson$.superClass_, _cmd);
// 调用 -[HcgPerson initWithName:age:] 方法的原始实现,并返回调用结果
return supFn (self, _cmd, aName, anAge);
}
// -[HcgPerson initWithName:age:] 方法的替换实现的函数声明
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
// 替换 -[HcgPerson initWithName:age:] 方法的实现
__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
{
// 获取 -[HcgPerson initWithName:age:] 方法的 Method 结构体(注意:会搜索父类的方法列表)
Method method = class_getInstanceMethod(HcgPerson$.class_, @selector(initWithName:age:));
if (method)
{
// 如果 HcgPerson 的类对象中或者 HcgPerson 的父类对象中,存在 -initWithName:age: 方法
// 获取指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
$HcgPerson_initWithName$age$_super = (__typeof__($HcgPerson_initWithName$age$_super))method_getImplementation(method);
// 向 HcgPerson 类对象中添加 -initWithName:age: 方法
if (class_addMethod(HcgPerson$.class_,
@selector(initWithName:age:),
(IMP)&$HcgPerson_initWithName$age$_method,
method_getTypeEncoding(method)))
{
// 如果方法添加成功,则说明 -initWithName:age: 方法是 HcgPerson 的父类对象的方法。此时:
// 通过宏接口 CHSuper_ 调用的是闭包函数 $HcgPerson_initWithName$age$_closure
// 而闭包函数 $HcgPerson_initWithName$age$_closure 会负责调用 HcgPerson 的父类对象中的 -initWithName:age: 方法实现
$HcgPerson_initWithName$age$_super = &$HcgPerson_initWithName$age$_closure;
}
else
{
// 如果方法添加失败,则说明 -initWithName:age: 方法是 HcgPerson 类对象的方法。此时:
// 将 -[HcgPerson initWithName:age:] 方法的实现设置为替换实现
// 通过宏接口 CHSuper_ 调用的是原先存储在 HcgPerson 类对象中 -initWithName:age: 方法的原始实现
method_setImplementation(method, (IMP)&$HcgPerson_initWithName$age$_method);
}
}
else
{
// 如果 HcgPerson 的类对象中和 HcgPerson 的父类对象中,都不存在 -initWithName:age: 方法
// 生成 -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge] 的方法签名
const char *return_ = @encode(HcgPerson*);
size_t return_len = __builtin_strlen(return_);
const char *type1_ = @encode(NSString*);
size_t type1_len = __builtin_strlen(type1_);
const char *type2_ = @encode(int);
size_t type2_len = __builtin_strlen(type2_);
char sig[return_len+2+type1_len+type2_len+1];
__builtin_memcpy(sig, return_, return_len);
sig[return_len] = '@';
sig[return_len+1] = ':';
__builtin_memcpy(&sig[return_len+2], type1_, type1_len);
__builtin_memcpy(&sig[return_len+2+type1_len], type2_, type2_len);
sig[return_len+type1_len+type2_len+2] = '\0';;
// 向 HcgPerson 类对象添加 -initWithName:age: 方法
class_addMethod(HcgPerson$.class_,
@selector(initWithName:age:),
(IMP)&$HcgPerson_initWithName$age$_method,
sig);
}
}
// -[HcgPerson initWithName:age:] 方法的替换实现
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
{
NSLog(@"CHMethod_ : hzp done!!!");
return ((void *)0);
}
static __attribute__((constructor)) void CHConstructor24()
{
CHLoadClass_(&HcgPerson$, objc_getClass("HcgPerson"));
$HcgPerson_initWithName$age$_register();
}
生成交换 Objective-C 方法实现的核心代码(CHMethod_super_)
在 CaptainHook.h
中,宏接口 CHMethod_super_
用于生成(交换 Objective-C 方法实现的核心代码),其定义为:
// @param.return_type 方法返回值的类型
// @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
// @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
// @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
// @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
// @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
// @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
// @param.supercall 调用闭包函数 xxx_closure 的参数列表
// @param.args... 方法的形参列表
#define CHMethod_super_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, args...) \
static return_type (*$ ## class_name ## _ ## name ## _super)(class_type self, SEL _cmd, ##args); \
static return_type $ ## class_name ## _ ## name ## _closure(class_type self, SEL _cmd, ##args) { \
typedef return_type (*supType)(class_type, SEL, ## args); \
supType supFn = (supType)class_getMethodImplementation(super_class_val, _cmd); \
return supFn supercall; \
} \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args); \
__attribute__((always_inline)) \
static inline void $ ## class_name ## _ ## name ## _register() { \
Method method = class_getInstanceMethod(class_val, @selector(sel)); \
if (method) { \
$ ## class_name ## _ ## name ## _super = (__typeof__($ ## class_name ## _ ## name ## _super))method_getImplementation(method); \
if (class_addMethod(class_val, @selector(sel), (IMP)&$ ## class_name ## _ ## name ## _method, method_getTypeEncoding(method))) { \
$ ## class_name ## _ ## name ## _super = &$ ## class_name ## _ ## name ## _closure; \
} else { \
method_setImplementation(method, (IMP)&$ ## class_name ## _ ## name ## _method); \
} \
} \
} \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args)
该宏接口做了四件事(以 Hook -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
为例):
-
定义了一个用于保存方法原始实现的函数指针(方法的原始实现,可能存储在当前类中,也可能存储在当前类的父类中)(供宏接口
CHSuper_
调用)static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
-
定义了一个用于调用方法原始实现的闭包函数(在此情景下,方法的原始实现存储在当前类的父类中)
static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
-
方法的替换实现的函数声明 + 方法的替换实现的函数实现
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
-
定义了一个用于(交换方法原始实现与方法替换实现)的注册函数(供宏接口
CHHook_
调用)__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register() { ... }
如下代码:
#import "HcgPerson.h"
#import "CaptainHook.h"
CHDeclareClass(HcgPerson)
// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHMethod_super_(HcgPerson*, // @param.return_type 方法返回值的类型
HcgPerson*, // @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
HcgPerson, // @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
CHClass(HcgPerson), // @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
CHSuperClass(HcgPerson), // @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
initWithName$age$, // @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
initWithName:age:, // @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
CHDeclareSig2_(HcgPerson*, NSString*, int), // @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
(self, _cmd, aName, anAge), // @param.supercall 调用闭包函数 xxx_closure 的参数列表
NSString* aName, // @param.args... 方法的形参列表
int anAge)
{
NSLog(@"CHMethod_super_ : hzp done!!!");
return nil;
}
CHConstructor
{
CHLoadLateClass(HcgPerson);
CHHook(2, HcgPerson, initWithName, age);
}
预处理后的结果为:
#pragma clang module import Foundation /* clang -E: implicit import for #import <Foundation/Foundation.h> */
#pragma clang assume_nonnull begin
@interface HcgPerson : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) int age;
-(instancetype)initWithName:(NSString *)aName age:(int)anAge;
+(instancetype)personWithName:(NSString *)aName age:(int)anAge;
-(NSString *)eatFood:(NSString *)aFood inPlace:(NSString *)aPlace;
+(int)doAdditionWithNum1:(int)num1 num2:(int)num2;
+(instancetype)sharedInstance;
@end
#pragma clang assume_nonnull end
#pragma clang module import ObjectiveC.runtime /* clang -E: implicit import for #import <objc/runtime.h> */
#pragma clang module import ObjectiveC.message /* clang -E: implicit import for #import <objc/message.h> */
#pragma clang module import Foundation.NSObject /* clang -E: implicit import for #import <Foundation/NSObject.h> */
#pragma clang module import Foundation.NSObjCRuntime /* clang -E: implicit import for #import <Foundation/NSObjCRuntime.h> */
struct CHClassDeclaration_
{
Class class_;
Class metaClass_;
Class superClass_;
};
typedef struct CHClassDeclaration_ CHClassDeclaration_;
static inline Class CHLoadClass_(CHClassDeclaration_* declaration, Class value)
{
declaration->class_ = value;
declaration->metaClass_ = object_getClass(value);
declaration->superClass_ = class_getSuperclass(value);
return value;
}
__attribute__((unused)) inline __attribute__((always_inline))
static void* CHIvar_(id object, const char * name)
{
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (ivar)
return (void *)&((char *)(__bridge void *)object)[ivar_getOffset(ivar)];
return ((void*)0);
}
@class HcgPerson;
static CHClassDeclaration_ HcgPerson$;
// 供宏接口 CHSuper_ 调用的函数指针,用于指向 -[HcgPerson initWithName:age:] 方法的原始实现
// 1.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的类对象中
// 则该函数指针指向 HcgPerson 的类对象中的 -initWithName:age: 方法实现
// 2.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的父类对象中
// 则该函数指针指向闭包函数 $HcgPerson_initWithName$age$_closure
// 而闭包函数 $HcgPerson_initWithName$age$_closure 会负责调用 HcgPerson 的父类对象中的 -initWithName:age: 方法实现
static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
// 用于调用存储在 HcgPerson 的父类对象中的 -initWithName:age: 方法的原始实现的闭包函数
static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
{
// 定义函数指针类型:supType
// supType 用于定义指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
typedef HcgPerson* (*supType)(HcgPerson*, SEL, NSString* aName, int anAge);
// 从 HcgPerson 的父类对象中,获取指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
supType supFn = (supType)class_getMethodImplementation(HcgPerson$.superClass_, _cmd);
// 调用 -[HcgPerson initWithName:age:] 方法的原始实现,并返回调用结果
return supFn (self, _cmd, aName, anAge);
}
// -[HcgPerson initWithName:age:] 方法的替换实现的函数声明
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
// 替换 -[HcgPerson initWithName:age:] 方法的实现
__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
{
// 获取 -[HcgPerson initWithName:age:] 方法的 Method 结构体(注意:会搜索父类的方法列表)
Method method = class_getInstanceMethod(HcgPerson$.class_, @selector(initWithName:age:));
if (method)
{
// 如果 HcgPerson 的类对象中或者 HcgPerson 的父类对象中,存在 -initWithName:age: 方法
// 获取指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
$HcgPerson_initWithName$age$_super = (__typeof__($HcgPerson_initWithName$age$_super))method_getImplementation(method);
// 向 HcgPerson 类对象中添加 -initWithName:age: 方法
if (class_addMethod(HcgPerson$.class_,
@selector(initWithName:age:),
(IMP)&$HcgPerson_initWithName$age$_method,
method_getTypeEncoding(method)))
{
// 如果方法添加成功,则说明 -initWithName:age: 方法是 HcgPerson 的父类对象的方法。此时:
// 通过宏接口 CHSuper_ 调用的是闭包函数 $HcgPerson_initWithName$age$_closure
// 而闭包函数 $HcgPerson_initWithName$age$_closure 会负责调用 HcgPerson 的父类对象中的 -initWithName:age: 方法实现
$HcgPerson_initWithName$age$_super = &$HcgPerson_initWithName$age$_closure;
}
else
{
// 如果方法添加失败,则说明 -initWithName:age: 方法是 HcgPerson 类对象的方法。此时:
// 将 -[HcgPerson initWithName:age:] 方法的实现设置为替换实现
// 通过宏接口 CHSuper_ 调用的是原先存储在 HcgPerson 类对象中 -initWithName:age: 方法的原始实现
method_setImplementation(method, (IMP)&$HcgPerson_initWithName$age$_method);
}
}
}
// -[HcgPerson initWithName:age:] 方法的替换实现
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
{
NSLog(@"CHMethod_super_ : hzp done!!!");
return ((void *)0);
}
static __attribute__((constructor)) void CHConstructor24()
{
CHLoadClass_(&HcgPerson$, objc_getClass("HcgPerson"));
$HcgPerson_initWithName$age$_register();
}
生成交换 Objective-C 方法实现的核心代码(CHMethod_self_)
在 CaptainHook.h
中,宏接口 CHMethod_self_
用于生成(交换 Objective-C 方法实现的核心代码),其定义为:
// @param.return_type 方法返回值的类型
// @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
// @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
// @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
// @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
// @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
// @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
// @param.supercall 调用闭包函数 xxx_closure 的参数列表
// @param.args... 方法的形参列表
#define CHMethod_self_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, args...) \
static return_type (*$ ## class_name ## _ ## name ## _super)(class_type self, SEL _cmd, ##args); \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args); \
__attribute__((always_inline)) \
static inline void $ ## class_name ## _ ## name ## _register() { \
Method method = class_getInstanceMethod(class_val, @selector(sel)); \
if (method) { \
$ ## class_name ## _ ## name ## _super = (__typeof__($ ## class_name ## _ ## name ## _super))method_getImplementation(method); \
method_setImplementation(method, (IMP)&$ ## class_name ## _ ## name ## _method); \
} \
} \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args)
该宏接口做了三件事(以 Hook -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
为例):
-
定义了一个用于保存方法原始实现的函数指针(方法的原始实现,可能存储在当前类中,也可能存储在当前类的父类中)(供宏接口
CHSuper_
调用)static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
-
方法的替换实现的函数声明 + 方法的替换实现的函数实现
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
-
定义了一个用于(交换方法原始实现与方法替换实现)的注册函数(供宏接口
CHHook_
调用)__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register() { ... }
如下代码:
#import "HcgPerson.h"
#import "CaptainHook.h"
CHDeclareClass(HcgPerson)
// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHMethod_self_(HcgPerson*, // @param.return_type 方法返回值的类型
HcgPerson*, // @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
HcgPerson, // @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
CHClass(HcgPerson), // @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
CHSuperClass(HcgPerson), // @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
initWithName$age$, // @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
initWithName:age:, // @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
CHDeclareSig2_(HcgPerson*, NSString*, int), // @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
(self, _cmd, aName, anAge), // @param.supercall 调用闭包函数 xxx_closure 的参数列表
NSString* aName, // @param.args... 方法的形参列表
int anAge)
{
NSLog(@"CHMethod_self_ : hzp done!!!");
return nil;
}
CHConstructor
{
CHLoadLateClass(HcgPerson);
CHHook(2, HcgPerson, initWithName, age);
}
预处理后的结果为:
#pragma clang module import Foundation /* clang -E: implicit import for #import <Foundation/Foundation.h> */
#pragma clang assume_nonnull begin
@interface HcgPerson : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) int age;
-(instancetype)initWithName:(NSString *)aName age:(int)anAge;
+(instancetype)personWithName:(NSString *)aName age:(int)anAge;
-(NSString *)eatFood:(NSString *)aFood inPlace:(NSString *)aPlace;
+(int)doAdditionWithNum1:(int)num1 num2:(int)num2;
+(instancetype)sharedInstance;
@end
#pragma clang assume_nonnull end
#pragma clang module import ObjectiveC.runtime /* clang -E: implicit import for #import <objc/runtime.h> */
#pragma clang module import ObjectiveC.message /* clang -E: implicit import for #import <objc/message.h> */
#pragma clang module import Foundation.NSObject /* clang -E: implicit import for #import <Foundation/NSObject.h> */
#pragma clang module import Foundation.NSObjCRuntime /* clang -E: implicit import for #import <Foundation/NSObjCRuntime.h> */
struct CHClassDeclaration_
{
Class class_;
Class metaClass_;
Class superClass_;
};
typedef struct CHClassDeclaration_ CHClassDeclaration_;
static inline Class CHLoadClass_(CHClassDeclaration_* declaration, Class value)
{
declaration->class_ = value;
declaration->metaClass_ = object_getClass(value);
declaration->superClass_ = class_getSuperclass(value);
return value;
}
__attribute__((unused)) inline __attribute__((always_inline))
static void* CHIvar_(id object, const char * name)
{
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (ivar)
return (void *)&((char *)(__bridge void *)object)[ivar_getOffset(ivar)];
return ((void*)0);
}
@class HcgPerson;
static CHClassDeclaration_ HcgPerson$;
// 供宏接口 CHSuper_ 调用的函数指针,用于指向 -[HcgPerson initWithName:age:] 方法的原始实现
// 1.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的类对象中
// 则该函数指针指向 HcgPerson 的类对象中的 -initWithName:age: 方法实现
// 2.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的父类对象中
// 则该函数指针指向 HcgPerson 的父类对象中的 -initWithName:age: 方法实现
static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
// -[HcgPerson initWithName:age:] 方法的替换实现的函数声明
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
// 替换 -[HcgPerson initWithName:age:] 方法的实现
__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
{
// 获取 -[HcgPerson initWithName:age:] 方法的 Method 结构体(注意:会搜索父类的方法列表)
Method method = class_getInstanceMethod(HcgPerson$.class_, @selector(initWithName:age:));
if (method)
{
// 如果 HcgPerson 的类对象中或者 HcgPerson 的父类对象中,存在 -initWithName:age: 方法
// 获取指向 -[HcgPerson initWithName:age:] 方法的原始实现的函数指针
$HcgPerson_initWithName$age$_super = (__typeof__($HcgPerson_initWithName$age$_super))method_getImplementation(method);
// 将 -initWithName:age: 方法的实现设置为替换实现
method_setImplementation(method, (IMP)&$HcgPerson_initWithName$age$_method);
}
}
// -[HcgPerson initWithName:age:] 方法的替换实现
static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
{
NSLog(@"CHMethod_self_ : hzp done!!!");
return ((void *)0);
}
static __attribute__((constructor)) void CHConstructor24()
{
CHLoadClass_(&HcgPerson$, objc_getClass("HcgPerson"));
$HcgPerson_initWithName$age$_register();
}
宏接口:CHMethod_ 、CHMethod_super_、CHMethod_self_ 的区别
在 CaptainHook .h
中,能够交换 Objective-C 方法实现的核心宏接口有:CHMethod_
、CHMethod_super_
、CHMethod_self_
因为这三个宏接口的底层都是通过调用 RunTime 的 API 来交换 Objective-C 方法的实现
所以这三个宏接口需要自己判断:被 Hook 的方法的实现,是存储在当前类中,还是存储在当前类的父类中,并做不同的处理,以统一返回一个能调用到被 Hook 方法的原始实现的函数指针
因此这三个宏接口在交换 Objective-C 方法实现的逻辑上有所不同
而这三个宏接口交换 Objective-C 方法实现的逻辑,主要体现在其所生成的注册函数中
以 Hook -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
方法为例:
由宏接口 CHMethod_
所生成的注册函数
__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
:
-
搜索
HcgPerson
的类对象及其父类对象,获取-initWithName:age:
方法的Method
结构体 -
如果
HcgPerson
的类对象或者父类对象中存在-initWithName:age:
方法,则-
如果
-initWithName:age:
方法存储在HcgPerson
的父类对象中,则在HcgPerson
的类对象中添加-initWithName:age:
方法(使用替换实现)此时调用宏接口
CHSuper_
将通过函数指针调用闭包函数$HcgPerson_initWithName$age$_closure
而闭包函数$HcgPerson_initWithName$age$_closure
会调用存储在HcgPerson
的父类对象中的-initWithName:age:
方法的原始实现 -
如果
-initWithName:age:
方法存储在HcgPerson
的类对象中,则将HcgPerson
类对象的-initWithName:age:
方法的实现设置为替换实现此时调用宏接口
CHSuper_
将通过函数指针直接调用-[HcgPerson initWithName:age:]
方法的原始实现
-
-
如果
HcgPerson
的类对象和父类对象中都不存在-initWithName:age:
方法,则在HcgPerson
的类对象中添加-initWithName:age:
方法(使用替换实现)此时调用宏接口
CHSuper_
将不会执行任何操作
由宏接口 CHMethod_super_
所生成的注册函数
__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
:
-
搜索
HcgPerson
的类对象及其父类对象,获取-initWithName:age:
方法的Method
结构体 -
如果
HcgPerson
的类对象或者父类对象中存在-initWithName:age:
方法,则-
如果
-initWithName:age:
方法存储在HcgPerson
的父类对象中,则在HcgPerson
的类对象中添加-initWithName:age:
方法(使用替换实现)此时调用宏接口
CHSuper_
将通过函数指针调用闭包函数$HcgPerson_initWithName$age$_closure
而闭包函数$HcgPerson_initWithName$age$_closure
会调用存储在HcgPerson
的父类对象中的-initWithName:age:
方法的原始实现 -
如果
-initWithName:age:
方法存储在HcgPerson
的类对象中,则将HcgPerson
类对象的-initWithName:age:
方法的实现设置为替换实现此时调用宏接口
CHSuper_
将通过函数指针直接调用-[HcgPerson initWithName:age:]
方法的原始实现
-
-
如果
HcgPerson
的类对象和父类对象中都不存在-initWithName:age:
方法,则不执行任何操作此时调用宏接口
CHSuper_
将不会执行任何操作
由宏接口 CHMethod_self_
所生成的注册函数
__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
:
-
搜索
HcgPerson
的类对象及其父类对象,获取-initWithName:age:
方法的Method
结构体 -
如果
HcgPerson
的类对象或者父类对象中存在-initWithName:age:
方法,则将-[HcgPerson initWithName:age:]
方法的实现设置为替换实现此时调用宏接口
CHSuper_
将通过函数指针直接调用-[HcgPerson initWithName:age:]
方法的原始实现 -
如果
HcgPerson
的类对象和父类对象中都不存在-initWithName:age:
方法,则不执行任何操作此时调用宏接口
CHSuper_
将不会执行任何操作
生成添加 Objective-C 方法的核心代码(CHMethod_new_)
在 CaptainHook.h
中,宏接口 CHMethod_new_
用于生成(添加 Objective-C 方法的核心代码),其定义为:
// @param.return_type 方法返回值的类型
// @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
// @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
// @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
// @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
// @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
// @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
// @param.supercall 调用闭包函数 xxx_closure 的参数列表
// @param.args... 方法的形参列表
#define CHMethod_new_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, args...) \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args); \
__attribute__((always_inline)) \
static inline void $ ## class_name ## _ ## name ## _register() { \
sigdef; \
class_addMethod(class_val, @selector(sel), (IMP)&$ ## class_name ## _ ## name ## _method, sig); \
} \
static return_type $ ## class_name ## _ ## name ## _method(class_type self, SEL _cmd, ##args)
该宏接口做了两件事(以添加 -(NSString *)[HcgPerson driveCar:(NSString *)aCar toPlace:(NSString *)aPlace]
为例):
-
要添加的方法的函数声明 + 要添加的方法的函数实现
static NSString* $HcgPerson_driveCar$toPlace$_method(HcgPerson* self, SEL _cmd, NSString* aCar, NSString* aPlace) { ... }
-
定义了一个用于(添加 Objective-C 方法)的注册函数(供宏接口
CHHook_
调用)__attribute__((always_inline)) static inline void $HcgPerson_driveCar$toPlace$_register() { ... }
如下代码:
#import "HcgPerson.h"
#import "CaptainHook.h"
CHDeclareClass(HcgPerson)
// -(NSString *)[HcgPerson driveCar:(NSString *)aCar toPlace:(NSString *)aPlace]
CHMethod_new_(NSString*, // @param.return_type 方法返回值的类型
HcgPerson*, // @param.class_type 方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
HcgPerson, // @param.class_name 方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
CHClass(HcgPerson), // @param.class_val 方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
CHSuperClass(HcgPerson), // @param.super_class_val 上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
driveCar$toPlace$, // @param.name 方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
driveCar:toPlace:, // @param.sel 方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
CHDeclareSig2_(NSString*, NSString*, NSString*), // @param.sigdef 计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
(self, _cmd, aCar, aPlace), // @param.supercall 调用闭包函数 xxx_closure 的参数列表
NSString* aCar, // @param.args... 方法的形参列表
NSString* aPlace)
{
return [NSString stringWithFormat:@"%@ drive %@ to %@", self.name, aCar, aPlace];
}
CHConstructor
{
CHLoadLateClass(HcgPerson);
CHHook(2, HcgPerson, driveCar, toPlace);
HcgPerson* p = [HcgPerson personWithName:@"hcg" age:20];
NSString* desc = [p driveCar:@"BYD" toPlace:@"XiaMen"];
NSLog(@"%@", desc);
}
预处理后的结果为:
#pragma clang module import Foundation /* clang -E: implicit import for #import <Foundation/Foundation.h> */
#pragma clang assume_nonnull begin
@interface HcgPerson : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) int age;
-(instancetype)initWithName:(NSString *)aName age:(int)anAge;
+(instancetype)personWithName:(NSString *)aName age:(int)anAge;
-(NSString *)eatFood:(NSString *)aFood inPlace:(NSString *)aPlace;
+(int)doAdditionWithNum1:(int)num1 num2:(int)num2;
+(instancetype)sharedInstance;
// 只有声明,没有实现
-(NSString *)driveCar:(NSString *)aCar toPlace:(NSString *)aPlace;
@end
#pragma clang assume_nonnull end
#pragma clang module import ObjectiveC.runtime /* clang -E: implicit import for #import <objc/runtime.h> */
#pragma clang module import ObjectiveC.message /* clang -E: implicit import for #import <objc/message.h> */
#pragma clang module import Foundation.NSObject /* clang -E: implicit import for #import <Foundation/NSObject.h> */
#pragma clang module import Foundation.NSObjCRuntime /* clang -E: implicit import for #import <Foundation/NSObjCRuntime.h> */
struct CHClassDeclaration_
{
Class class_;
Class metaClass_;
Class superClass_;
};
typedef struct CHClassDeclaration_ CHClassDeclaration_;
static inline Class CHLoadClass_(CHClassDeclaration_* declaration, Class value)
{
declaration->class_ = value;
declaration->metaClass_ = object_getClass(value);
declaration->superClass_ = class_getSuperclass(value);
return value;
}
__attribute__((unused)) inline __attribute__((always_inline))
static void* CHIvar_(id object, const char * name)
{
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (ivar)
return (void *)&((char *)(__bridge void *)object)[ivar_getOffset(ivar)];
return ((void*)0);
}
@class HcgPerson;
static CHClassDeclaration_ HcgPerson$;
// -[HcgPerson driveCar:toPlace:] 方法实现的函数声明
static NSString* $HcgPerson_driveCar$toPlace$_method(HcgPerson* self, SEL _cmd, NSString* aCar, NSString* aPlace);
// 添加 -[HcgPerson driveCar:toPlace:] 方法
__attribute__((always_inline)) static inline void $HcgPerson_driveCar$toPlace$_register()
{
// 生成 -(NSString *)[HcgPerson driveCar:(NSString *)aCar toPlace:(NSString *)aPlace] 的方法签名
const char *return_ = @encode(NSString*);
size_t return_len = __builtin_strlen(return_);
const char *type1_ = @encode(NSString*);
size_t type1_len = __builtin_strlen(type1_);
const char *type2_ = @encode(NSString*);
size_t type2_len = __builtin_strlen(type2_);
char sig[return_len+2+type1_len+type2_len+1];
__builtin_memcpy(sig, return_, return_len);
sig[return_len] = '@';
sig[return_len+1] = ':';
__builtin_memcpy(&sig[return_len+2], type1_, type1_len);
__builtin_memcpy(&sig[return_len+2+type1_len], type2_, type2_len);
sig[return_len+type1_len+type2_len+2] = '\0';;
// 向 HcgPerson 类对象添加 -driveCar:toPlace: 方法
class_addMethod(HcgPerson$.class_,
@selector(driveCar:toPlace:),
(IMP)&$HcgPerson_driveCar$toPlace$_method,
sig);
}
// -[HcgPerson driveCar:toPlace:] 方法实现的函数实现
static NSString* $HcgPerson_driveCar$toPlace$_method(HcgPerson* self, SEL _cmd, NSString* aCar, NSString* aPlace)
{
return [NSString stringWithFormat:@"%@ drive %@ to %@", self.name, aCar, aPlace];
}
static __attribute__((constructor)) void CHConstructor23()
{
CHLoadClass_(&HcgPerson$, objc_getClass("HcgPerson"));
$HcgPerson_driveCar$toPlace$_register();
HcgPerson* p = [HcgPerson personWithName:@"hcg" age:20];
NSString* desc = [p driveCar:@"BYD" toPlace:@"XiaMen"];
NSLog(@"%@", desc);
}