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

计算方法的类型编码(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] 为例):

  1. 定义了一个用于保存方法原始实现的函数指针(方法的原始实现,可能存储在当前类中,也可能存储在当前类的父类中)(供宏接口 CHSuper_ 调用)

    static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
    
  2. 定义了一个用于调用方法原始实现的闭包函数(在此情景下,方法的原始实现存储在当前类的父类中)

    static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
    
  3. 方法的替换实现的函数声明 + 方法的替换实现的函数实现

    static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
    
  4. 定义了一个用于(交换方法原始实现与方法替换实现)的注册函数(供宏接口 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] 为例):

  1. 定义了一个用于保存方法原始实现的函数指针(方法的原始实现,可能存储在当前类中,也可能存储在当前类的父类中)(供宏接口 CHSuper_ 调用)

    static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
    
  2. 定义了一个用于调用方法原始实现的闭包函数(在此情景下,方法的原始实现存储在当前类的父类中)

    static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
    
  3. 方法的替换实现的函数声明 + 方法的替换实现的函数实现

    static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
    
  4. 定义了一个用于(交换方法原始实现与方法替换实现)的注册函数(供宏接口 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] 为例):

  1. 定义了一个用于保存方法原始实现的函数指针(方法的原始实现,可能存储在当前类中,也可能存储在当前类的父类中)(供宏接口 CHSuper_ 调用)

    static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
    
  2. 方法的替换实现的函数声明 + 方法的替换实现的函数实现

    static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge) { ... }
    
  3. 定义了一个用于(交换方法原始实现与方法替换实现)的注册函数(供宏接口 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] 为例):

  1. 要添加的方法的函数声明 + 要添加的方法的函数实现

    static NSString* $HcgPerson_driveCar$toPlace$_method(HcgPerson* self, SEL _cmd, NSString* aCar, NSString* aPlace) { ... }
    
  2. 定义了一个用于(添加 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值