runtime.h(三)

版本:iOS13.5

runtime.h

需要引入头文件#import
runtime其他方法通道

索引

  • 获取已命名类的id。(ARC模式下不可用 )
    objc_getFutureClass
  • 创建一个类的实例,并在默认的malloc内存区域中为该类分配内存。
    class_createInstance
  • 在提供的特定位置创建类的实例。(ARC模式不可用)
    objc_constructInstance
  • 在不释放内存的情况下销毁类的实例,并删除该实例可能具有的所有关联引用。(ARC模式不可用)
    objc_destructInstance
  • 创建一个新的类和元类。
    objc_allocateClassPair
  • 注册并使用该类。
    objc_registerClassPair
  • 获取重复的类。
    objc_duplicateClass
  • 销毁一个类及其相关的元类。
    objc_disposeClassPair
  • 获取方法的选择器。
    method_getName
  • 返回方法的实现指针。
    method_getImplementation
  • 返回方法的描述参数和返回类型的字符串。
    method_getTypeEncoding
  • 返回方法接受的参数数量。
    method_getNumberOfArguments
  • 返回方法的描述返回类型的字符串。
    method_copyReturnType
  • 返回方法的描述单个参数类型的字符串。
    method_copyArgumentType
  • 获取方法的描述返回类型的字符串。
    method_getReturnType
  • 获取方法的描述单个参数类型的字符串。
    method_getArgumentType
  • 返回方法的描述结构体。
    method_getDescription
  • 为方法设置新的实现指针。
    method_setImplementation
  • 交换两种方法的实现指针。
    method_exchangeImplementations

详解

  • 获取已命名类的id。(ARC模式下不可用 )
Class _Nonnull objc_getFutureClass(const char * _Nonnull name) OBJC_ARC_UNAVAILABLE

警告:你不应该调用该函数

返回命名类的ID,或在加载时(如果加载)将用于该类的未初始化的类结构体。

  • 创建一个类的实例,并在默认的malloc内存区域中为该类分配内存。
id _Nullable class_createInstance(Class _Nullable cls, size_t extraBytes)

extraBytes 要分配的额外字节数。除类中已定义的变量外,额外字节可用于存储其他实例变量。
id 返回该类的实例

例:
id instance = class_createInstance(object_getClass(self), 0);
  • 在提供的特定位置创建类的实例。(ARC模式不可用)
id _Nullable objc_constructInstance(Class _Nullable cls, void * _Nullable bytes) 
OBJC_ARC_UNAVAILABLE

bytes 实例的位置。需要指向对齐良好的零填充内存,且必须至少class_getInstanceSize字节

  • 在不释放内存的情况下销毁类的实例,并删除该实例可能具有的所有关联引用。(ARC模式不可用)
void * _Nullable objc_destructInstance(id _Nullable obj) OBJC_ARC_UNAVAILABLE

obj 类的实例,通过objc_constructInstance创建

  • 创建一个新的类和元类。
Class _Nullable objc_allocateClassPair(Class _Nullable superclass,
                const char * _Nonnull name, size_t extraBytes) 

要创建新类,请先调用objc_allocateClassPair,然后使用class_addMethodclass_addIvar之类的函数设置类的方法和属性,最后调用objc_registerClassPair,就可以使用新类了。
其中实例方法和实例变量添加到类本身。类方法应添加到元类。

superclass 创建的类的父类,传nil表示创建新的根类。
name 新类的名字的字符串,该字符串将被复制。
extraBytes 在类和元类对象末尾为已索引的ivars分配的字节数。通常应为0。
Class 返回新类 若已有同名的类,则返回nil。
例子见objc_registerClassPair

  • 注册并使用该类。
void objc_registerClassPair(Class _Nonnull cls) 

cls 该类必须是通过objc_allocateClassPair创建的

例:
    Class Model = objc_allocateClassPair(objc_getClass("NSObject"), "Model", 0);
    //添加变量
    class_addIvar(Model, "adress", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
    //添加方法
    SEL getInfo = @selector(getInfo);
    IMP getInfoImp = class_getMethodImplementation(Model, getInfo);
    class_addMethod(Model, getInfo, getInfoImp, "v@:");
    objc_registerClassPair(Model);
    id model = class_createInstance(Model, 0);
    NSLog(@"%@ %s %@", model,
          ivar_getName(class_getInstanceVariable(Model, "adress")),
          NSStringFromSelector(method_getName(class_getInstanceMethod(Model, getInfo))));
输出:
 adress getInfo
  • 获取重复的类。
Class _Nonnull objc_duplicateClass(Class _Nonnull original, const char * _Nonnull name,
                    size_t extraBytes)

由Foundation使用。
警告:你不应该调用该函数。

  • 销毁一个类及其相关的元类。
void objc_disposeClassPair(Class _Nonnull cls) 

如果存在此类或子类的实例,请不要调用。

cls 要销毁的类 它必须是使用objc_allocateClassPair进行创建的。

  • 获取方法的选择器。
SEL _Nonnull method_getName(Method _Nonnull m) 

m 方法
通过class_getInstanceMethod获取实例方法
通过class_getClassMethod获取类方法
SEL 返回选择器 可通过sel_getName获取选择器的名称
例子见method_getTypeEncoding

  • 返回方法的实现指针。
IMP _Nonnull method_getImplementation(Method _Nonnull m) 

例子见method_getTypeEncoding

  • 返回方法的描述参数和返回类型的字符串。
const char * _Nullable method_getTypeEncoding(Method _Nonnull m) 
例:
    Method method1 = class_getInstanceMethod(object_getClass(self), @selector(getPhoneWithName:));
    //获取方法的选择器
    SEL method1Sel = method_getName(method1);
    NSLog(@"%s", sel_getName(method1Sel));
    //获取方法的实现指针
    IMP method1IMP = method_getImplementation(method1);
    //获取方法的返回类型与参数的描述字符串
    const char *method1Char = method_getTypeEncoding(method1);
    NSLog(@"%s", method1Char);
- (NSNumber *)getPhoneWithName:(NSString *)name {
    NSLog(@"%@", name);
    return @(13111111111);
}
输出:
getPhoneWithName:
@24@0:8@16
  • 返回方法接受的参数数量。
unsigned int method_getNumberOfArguments(Method _Nonnull m)

例子见method_copyArgumentType

  • 返回方法的描述返回类型的字符串。
char * _Nonnull method_copyReturnType(Method _Nonnull m) 

你必须通过free释放字符串。

例子见method_copyArgumentType

  • 返回方法的描述单个参数类型的字符串。
char * _Nullable method_copyArgumentType(Method _Nonnull m, unsigned int index) 

你必须通过free释放字符串。

index 要查询的参数的索引 从2开始 前2个参数已被系统使用
char * 如果方法没有对应索引的参数,则返回NULL。

例:
    Method method1 = class_getInstanceMethod(object_getClass(self), @selector(getPhoneWithName:));
    unsigned int arguments = method_getNumberOfArguments(method1);
    char *returnType = method_copyReturnType(method1);
    //参数从第三个开始算
    char *argumentType = method_copyArgumentType(method1, 2);
    NSLog(@"%d %s %s", arguments, returnType, argumentType);

- (NSNumber *)getPhoneWithName:(NSString *)name {
    NSLog(@"%@", name);
    return @(13111111111);
}
输出:
3 @ @
method_getTypeEncoding例子输出的@24@0:8@16 @24表示返回参数 对应上面的第一个@
@0表示3个参数中的第一个 :8表示参数的第二个 这两个已经被系统使用
@16表示参数的第三个,也是自己定义的参数name,对应下面的第二个@
  • 获取方法的描述返回类型的字符串。
void method_getReturnType(Method _Nonnull m, char * _Nonnull dst, size_t dst_len) 

dst 存储描述的字符串 需要给dst通过malloc分配内存
dst_len dst可以存储的最大字节数
例子见method_getDescription

  • 获取方法的描述单个参数类型的字符串。
void method_getArgumentType(Method _Nonnull m, unsigned int index,
                       char * _Nullable dst, size_t dst_len) 

index 要查询的参数的索引 从2开始 前2个参数已被系统使用
dst 存储描述的字符串 需要给dst通过malloc分配内存
dst_len dst可以存储的最大字节数
例子见method_getDescription

  • 返回方法的描述结构体。
struct objc_method_description * _Nonnull method_getDescription(Method _Nonnull m) 

objc_method_description 返回的结构体

struct objc_method_description {
    //方法的选择器
    SEL _Nullable name;
    //方法的参数类型
    char * _Nullable types;
};
例:
    char *returnType1 = malloc(10);
    method_getReturnType(method1, returnType1, 10);
    char *argumentType1 = malloc(10);
    method_getArgumentType(method1, 2, argumentType1, 10);
    NSLog(@"%s %s", returnType1, argumentType1);
    free(returnType1);
    free(argumentType1);
    struct objc_method_description *des = method_getDescription(method1);
    struct objc_method_description desInfo = des[0];
    NSLog(@"%@ %s", NSStringFromSelector(desInfo.name), desInfo.types);

- (NSNumber *)getPhoneWithName:(NSString *)name {
    NSLog(@"%@", name);
    return @(13111111111);
}
输出:
@ @
getPhoneWithName: @24@0:8@16
  • 为方法设置新的实现指针。
IMP _Nonnull method_setImplementation(Method _Nonnull m, IMP _Nonnull imp) 

详细说明见方法class_addMethod

imp 新的方法实现指针
IMP 返回之前的指针
例子见method_exchangeImplementations

  • 交换两种方法的实现指针。
void method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2) 

效果如同下面代码

IMP imp1 = method_getImplementation(m1);
IMP imp2 = method_getImplementation(m2);
method_setImplementation(m1, imp2);
method_setImplementation(m2, imp1);
例:
    Method a = class_getInstanceMethod(object_getClass(self), NSSelectorFromString(@"a"));
    Method b = class_getInstanceMethod(object_getClass(self), NSSelectorFromString(@"b"));
    [self a];
    [self b];
    method_exchangeImplementations(a, b);
    [self a];
    [self b];

- (void)a {
    NSLog(@"aaa");
}

- (void)b {
    NSLog(@"bbb");
}
输出:
aaa
bbb
bbb
aaa

你可能感兴趣的:(runtime.h(三))