runtime.h(三)

2020-08-10  本文已影响0人  想聽丿伱說衹愛我

版本:iOS13.5

runtime.h

需要引入头文件#import <objc/runtime.h>
runtime其他方法通道

索引

详解

Class _Nonnull objc_getFutureClass(const char * _Nonnull name) OBJC_ARC_UNAVAILABLE

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

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

id _Nullable class_createInstance(Class _Nullable cls, size_t extraBytes)

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

例:
id instance = class_createInstance(object_getClass(self), 0);
id _Nullable objc_constructInstance(Class _Nullable cls, void * _Nullable bytes) 
OBJC_ARC_UNAVAILABLE

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

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))));
输出:
<Model: 0x6000010405d0> 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
上一篇 下一篇

猜你喜欢

热点阅读