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);