Runtime函数库中关于 Class 的函数使用

Runtime 函数库提供了很多函数用于一些操作,本篇主要总结关于类 Class 的操作函数:

1、根据类名获取类

/* 获取指定名称的类:
 * @param name 要查找的类的名称。
 * @return 返回指定名称的类;
 * @note 如果类没有在Objective-C运行时注册,则返回 nil。
 * @note 如果该类不存在,调用 _objc_classLoader() 函数,然后调用objc_classHandler() 函数,两者都可以创建一个新类。
 * @note objc_getClass() 与objc_lookUpClass() 的不同之处在于,如果类没有注册,objc_getClass() 将调用类处理程序回调,然后再次检查类是否注册。objc_lookUpClass() 不调用类处理程序回调。
 * @Warning: 如果aClassName是为类的 isa 设置的名称,则无法执行!
 */
Class _Nullable objc_getClass(const char * _Nonnull name);

/* 获取指定名称的类:
 * @note 该函数功能基于 objc_getClass() 函数,内部首先调用 objc_getClass() 函数获取返回值;
 *       然后判断返回值是否为空,如果返回值为空,则终止进程;
 * @note 此函数由 ZeroLink 使用,如果没有 ZeroLink,则无法找到类将是编译时链接错误。
 */
Class _Nonnull objc_getRequiredClass(const char * _Nonnull name);

/* 获取指定名称的类
 * @note 如果类没有在Objective-C运行时注册,则返回 nil。
 *       如果该类不存在, 调用_objc_classLoader() 函数,它可以创建一个新类。
 * @note objc_getClass() 与这个函数的不同之处在于,如果类没有注册,objc_getClass() 将调用类处理程序回调函数,然后第二次检查类是否注册。这个函数不调用类处理程序回调。
 */
Class _Nullable objc_lookUpClass(const char * _Nonnull name);

/* 获取指定名称的类的元类
 * @note 如果指定名称的类不存在,则返回 nil 并且打印日志 objc[3966]: class `aClassName' not linked into application
 * @note 如果命名类的定义未注册,则此函数调用类处理程序回调,然后再次检查类是否注册。但是,每个类定义都必须有一个有效的元类定义,因此无论元类定义是否有效,它总是返回。
 */
Class _Nullable objc_getMetaClass(const char * _Nonnull name);

/* 获取指定数量的已注册类,获取的类列表为任意子集。
 * @param buffer 用于写入已注册类集的缓存;最多有 bufferCount 或注册类的总数量(以较少者为准)。
 *               可以传递NULL来获取注册类定义的总数:
 * @param bufferCount 指定获取类的数量;
 * @return 返回已注册类的总数量。
 * @note  该次函数执行 objc_getClassList(NULL, 0) 获取所有已注册类的总数量;
 * @note Objective-C 运行库自动注册在源代码中定义的所有类;
 *       可以在运行时创建类定义,并将它们注册到objc_addClass() 函数中。
 * @warning 该函数中获得的类的父类可能是任意类;因此如果不首先检测方法的实现,就不能安全地调用这些类上的任何方法。
 */
int objc_getClassList(Class _Nonnull * _Nullable buffer, int bufferCount);

/* 获取所有已注册类的指针列表。
 * @param outCount 所有已注册类数量
 * @note 该函数与 objc_getClassList() 函数区别在于:
 *       该函数只能获取所有已注册的类;但是用法简单
 *       objc_getClassList() 函数可以获取指定数量的任意集合类;用法稍微复杂些;
 */
Class _Nonnull * _Nullable objc_copyClassList(unsigned int * _Nullable outCount);

2、使用类

2.1、获取类的一些简单信息
/* 获取指定类的类名
 * @param cls 类.
 * @return 如果 class 为 nil,则返回空字符串
 */
const char *class_getName(Class cls);

/* 判断指定类是否是元类
 */
BOOL class_isMetaClass(Class cls) ;

/* 获取指定类的父类
 * @note 如果该类是 NSObject,则返回 nil;如果 cls为 nil, 则返回 nil;
 */
Class class_getSuperclass(Class cls);

/* 设置指定类的父类
 *
 * @param cls 要设置的指定类
 * @param newSuper 指定类的新父类
 * @return 指定类的原有父类
 */
Class class_setSuperclass(Class cls, Class newSuper);

/* 获取类定义的版本号。
 */
int class_getVersion(Class cls);

/* 设置类定义的版本号。
 * @param version 新的版本号,int 型数据类型
 * @note 可以使用类定义的版本号来提供类表示给其他类的接口的版本控制。
 *       这对于对象序列化特别有用,在这种情况下,识别不同类定义版本中实例变量布局的更改非常重要。
 */
void class_setVersion(Class cls, int version);

/* 获取指定类的实例大小(字节数)
 * @return 如果 cls 为nil,则返回 0 字节。
 */
size_t class_getInstanceSize(Class cls);
2.2、获取类的变量
/* 获取指定类的 指定实例变量 Ivar。
 * @param cls 指定实例对象所属的类
 * @param name 要获取的实例变量的定义名称
 * @return 一个指向 Ivar 数据结构的指针,该结构包含关于由名称指定的实例变量的信息。
 */
Ivar class_getInstanceVariable(Class cls, const char *name);

/* 获取指定类的 指定类变量 Ivar。
 * @param cls 指定类
 * @param name 要获取的类变量的定义名称
 */
Ivar class_getClassVariable(Class cls, const char *name);

/* 获取由指定类声明的所有实例变量
 * @param cls 指定的类。
 * @param outCount 返回数组的长度;如果为 NULL,则不返回长度。
 * @return 类型为Ivar的指针数组,描述类声明的实例变量。
 *         不包括由超类声明的任何实例变量。
 *         必须使用 free() 函数释放数组。
 *
 *  如果类声明没有实例变量,或者 cls 为Nil,则返回 NULL 并 *outCount 值为 0。
 */
Ivar *class_copyIvarList(Class cls, unsigned int *outCount);

/* 获取指定类的变量 Ivar 布局的描述。
 */
const uint8_t *class_getIvarLayout(Class cls);

/* 设置指定类的 Ivar 布局。
 */
void class_setIvarLayout(Class cls, const uint8_t *layout);

/* 获取指定类的弱引用变量 Ivars 布局的描述。
 */
const uint8_t *class_getWeakIvarLayout(Class cls);

/* 设置指定类的弱引用变量 Ivars 布局。
 */
void class_setWeakIvarLayout(Class cls, const uint8_t *layout);

/* 向指定类添加新实例变量。
 * @return 如果实例变量添加成功返回 YES;则为 NO 如该类已经包含一个同名的实例变量
 * @note 此函数只能在 objc_allocateClassPair() 函数之后和 objc_registerClassPair() 函数之前调用;
 *       不支持向现有类中添加实例变量。
 * @note 指定类不能是元类;不支持向元类中添加实例变量。
 * @note 实例变量的最小字节对齐是 1<
2.3、获取类的属性
/* 获取指定类的指定名称的属性。
 * @param name 指定属性的名称。
 * @return 如果类没有使用该名称声明属性,则返回 NULL;如果cls为 Nil,则返回NULL。
 */
objc_property_t class_getProperty(Class cls, const char *name);

/* 获取指定类声明的所有属性。
 * @param outCount 返回数组的长度;如果为 NULL,则不返回长度。
 * @return 返回类型为 objc_property_t 的指针数组,用于描述该类声明的属性。
 *         不包括父类声明的任何属性。
 *         必须使用free()释放数组。
 * 如果cls 声明没有属性,或者 cls 为 Nil,则返回 NULL 且 *outCount 值为 0。
 */
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount);

/* 向指定类中添加属性。
 * @param name 属性名称.
 * @param attributes 属性特征数组.
 * @param attributeCount 属性特征数组元素数量.
 * @return 如果属性添加成功返回 YES;则为 NO 如该类已经存在该属性
 */
BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount);

/* 替换指定类的某个属性。
 * @param name 要替换的属性名称.
 * @param attributes 属性特征数组.
 * @param attributeCount 属性特征数组元素数量.
 */
void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
2.4、获取类的方法
/* 获取指定类的指定实例方法。
 * @param name 要获取方法的选择器类型。
 * @return 如果指定的类或其父类不包含具有指定选择器的实例方法,则返回 NULL。
 * @note 该函数会去父类中搜索,而 class_copyMethodList() 函数不会去父类中搜索。
 */
Method class_getInstanceMethod(Class cls, SEL name);

/* 获取指定类的指定类方法。
 * @return 如果指定的类或其父类不包含具有指定选择器的类方法,则返回 NULL。
 * @note 该函数会去父类中搜索,而 class_copyMethodList() 函数不会去父类中搜索。
 */
Method class_getClassMethod(Class cls, SEL name);

/* 获取指定类实现的所有实例方法。
 * @param outCount 返回数组的长度;如果为 NULL,则不返回长度。
 * @return 获取类实现的实例方法的类型指针数组;
 *         不包括由父类实现的任何实例方法;必须使用 free() 函数释放数组。
 * @note 如果 cls 没有实现实例方法,或者 cls 为 Nil,则返回 NULL 且 *outCount 值为 0。
 * @note 要获取类的类方法,使用 class_copyMethodList(object_getClass(cls), &count).
 * @note 要获得父类可能实现的方法的实现,可以使用 class_getInstanceMethod() 函数 或者 class_getClassMethod() 函数.
 */
Method *class_copyMethodList(Class cls, unsigned int *outCount);

/* 获取在将指定消息发送到类的实例时将调用的函数指针。
 * @return 如果cls为 nil,则返回空指针 NULL
 *
 * @note  该函数在运行效率上可能比 method_getImplementation(class_getInstanceMethod(cls, name)) 更快
 * @note 返回的函数指针可能是运行时的内部函数,而不是实际的方法实现。
 *       例如,如果类的实例不响应 SEL,返回的函数指针将成为运行时消息转发机制的一部分。
 */
IMP class_getMethodImplementation(Class cls, SEL name);

/* 获取在将指定消息发送到类的实例时将调用的函数指针。
 * @return 如果cls为 nil,则返回空指针 NULL
 */
IMP class_getMethodImplementation_stret(Class cls, SEL name);

/* 判断指定类的实例能否响应指定选择器。
 * @prama cls 指定类的实例
 * @param sel 指定选择器
 * @return 如果类的实例响应选择器,则为YES,否则为NO。
 * @note 一般使用 NSObject 的 -respondsToSelector: 方法或者 +instancesRespondToSelector: 方法来替代这个函数
 */
BOOL class_respondsToSelector(Class cls, SEL sel);

/* 向指定类添加新方法
 * @param cls 要添加方法的类。
 * @param name 指定要添加方法的选择器 SEL。
 * @param imp 函数指针,该函数必须具有至少两个参数 self 和 _cmd 。
 * @param types 描述方法参数类型的字符数组。
 * @return 如果方法添加成功,则为YES;否则为 NO,如添加该类已实现的方法则失败
 * @note 该函数将重写父类的方法,但不会替换该类中的现有方法。要更改现有的实现,使用 method_setImplementation() 函数。
 */
BOOL class_addMethod(Class cls, SEL name, IMP imp,const char *types);

/* 替换指定类的方法的实现。
 * @param name 要替换其实现方法的选择器 SEL
 * @param imp 新的函数地址
 * @param types 描述方法参数类型的字符数组。
 * @return 指定类的方法的原有实现;
 * @note 这个函数有两种不同的行为方式:
 *  - 如果该方法还不存在,那么就像调用 class_addMethod() 函数一样添加它;types 将按给定的方式使用。
 *  - 如果该方法已经实现,则替换其IMP,就像调用 method_setImplementation() 函数一样;忽略 types。
 */
IMP class_replaceMethod(Class cls, SEL name, IMP imp,const char *types);
2.5、获取类的协议
/* 判断指定类是否实现了指定的协议。
 * @param cls 指定类
 * @param protocol 指定的协议.
 * @return 如果cls 实现协议,则为YES,否则为NO。
 * @note 一般使用 NSObject 的 -conformsToProtocol: 方法来替代这个函数
 */
BOOL class_conformsToProtocol(Class cls, Protocol *protocol);

/* 获取指定类所声明的所有协议
 * @param outCount 返回数组的长度;如果为 NULL,则不返回长度。
 * @return 返回类型为 Protocol* 的指针数组,描述类所声明的协议。
 *         不包括父类或其他协议所声明的任何协议;
 *         必须使用 free() 函数释放数组;
 *  如果 cls 不采用协议,或者 cls 为 Nil,则返回 NULL 且 *outCount 值为 0。
 */
Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount);

/* 向指定类中添加协议。
 * @return 如果协议添加成功返回 YES;则为 NO 如该类已经声明该协议
 */
BOOL class_addProtocol(Class cls, Protocol *protocol);

/* 用于CoreFoundation的桥接。
 * @warning 不要自己调用这个函数。
 */
Class _Nonnull objc_getFutureClass(const char * _Nonnull name);

3、动态添加类

/* 创建一个新类和元类。
 * @param superclass 要用作新类的父类;如果为 nil 则创建根类。
 * @param name 用作新类名称的字符串;字符串将被复制。
 * @param extraBytes 在类和元类对象的末尾为索引ivars分配的字节数。这通常是0。
 * @return 返回新类;如果无法创建类则为Nil(例如,所需的名称已经在使用中)。
 * @note 通过调用 object_getClass(newClass) 来获得指向新元类的指针。
 * @note 要创建一个新类,首先调用 objc_allocateClassPair() 。
 *       然后使用class_addMethod() 和class_addIvar() 等函数设置类的属性。
 *       构建完类后,调用 objc_registerClassPair() 注册类。
 *       新类现在可以使用了。
 * @note 实例方法和实例变量应该添加到类本身;类方法应该添加到元类中。
 */
Class _Nullable objc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name,size_t extraBytes);

/* 注册使用 objc_allocateClassPair() 创建的类。
 */
void objc_registerClassPair(Class _Nonnull cls);

/* 用于Foundation的键值观察。
 * @warning 不要自己调用这个函数。
 */
Class _Nonnull objc_duplicateClass(Class _Nonnull original, const char * _Nonnull name,size_t extraBytes);

/* 销毁一个类及其关联的元类;
 * @param cls 要销毁的类必须是用objc_allocateClassPair() 创建的;
 * @warning 如果存在此类或子类的实例,则不要调用。
 */
void objc_disposeClassPair(Class _Nonnull cls);

你可能感兴趣的:(Runtime函数库中关于 Class 的函数使用)