Runtime 函数库提供了很多函数用于一些操作,本篇主要总结关于方法 Method
的操作函数:
/* 返回指定类的指定实例方法。
* @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() 函数释放数组。
*
* 如果 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);
1、使用方法
/* 获取方法的选择器
*/
SEL _Nonnull method_getName(Method _Nonnull m);
/* 获取方法的函数地址。
*/
IMP _Nonnull method_getImplementation(Method _Nonnull m);
/* 获取方法的参数类型和返回值类型;可能为 NULL
*/
const char * _Nullable method_getTypeEncoding(Method _Nonnull m);
/* 获取方法的参数数量。
*/
unsigned int method_getNumberOfArguments(Method _Nonnull m);
/* 获取方法的返回值类型
* @return 描述返回类型的C字符串。必须使用 free() 函数释放字符串。
*/
char * _Nonnull method_copyReturnType(Method _Nonnull m);
/* 获取方法的中指定索引位置的参数类型
* @param index 参数的索引。
* @return 一个C字符串,描述在索引索引处的参数类型;如果方法没有参数索引,则为NULL;必须使用free()释放字符串。
*/
char * _Nullable method_copyArgumentType(Method _Nonnull m, unsigned int index);
/* 获取返回值类型。
* @param dst 存储描述的引用字符串
* @param dst_len 可以存储在dst中的最大字符数。
* @note 方法的返回类型字符串复制到dst;就像调用 strncpy(dst, parameter_type, dst_len) 一样填充dst。
*/
void method_getReturnType(Method _Nonnull m, char * _Nonnull dst, size_t dst_len);
/* 获取方法的中指定索引位置的参数类型
* @param index 参数的索引。
* @param dst 存储描述的引用字符串。
* @param dst_len 可以存储在dst中的最大字符数。
* @note 参数类型字符串复制到 dst ;就像调用 strncpy(dst, parameter_type, dst_len) 一样填充d st。
* 如果该方法不包含具有该索引的参数,则将 dst 填充为调用 strncpy(dst, "", dst_len)。
*/
void method_getArgumentType(Method _Nonnull m, unsigned int index,char * _Nullable dst, size_t dst_len);
/* 获取方法的描述结构体
*/
struct objc_method_description * _Nonnull method_getDescription(Method _Nonnull m);
/* 设置方法的实现。
* @return 返回该方法的原有 IMP
*/
IMP _Nonnull method_setImplementation(Method _Nonnull m, IMP _Nonnull imp);
/* 交换两个方法的实现。
* @note 以下代码是细微实现:
* IMP imp1 = method_getImplementation(m1);
* IMP imp2 = method_getImplementation(m2);
* method_setImplementation(m1, imp2);
* method_setImplementation(m2, imp1);
*/
void method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2);
2、使用选择器
/* 获取指定选择器的对应方法的名称。
* @param sel 选择器类型 SEL
* @return 选择器名称
*/
const char * _Nonnull sel_getName(SEL _Nonnull sel);
/* 向 Objective-C 运行时系统注册一个方法,将方法名映射到选择器,并返回选择器值。
* @param str 要注册的方法的名称
* @return 指定方法的选择器。
* @note 在将方法添加到类定义之前,必须向 Objective-C 运行时系统注册方法名,以获得方法的选择器。
* 如果方法名已经注册,则该函数只返回选择器。
*/
SEL _Nonnull sel_registerName(const char * _Nonnull str);
/* 判断两个选择器是否相等。
* @return 如果相等则为YES,否则为NO。
* @note 该函数等价于 ==
*/
BOOL sel_isEqual(SEL _Nonnull lhs, SEL _Nonnull rhs);
/* 判断选择器为有效或无效。
* @param sel 要标识的选择器。
* @return 如果选择器有效且具有函数实现,则为YES,否则为NO。
* @warning 在某些平台上,无效引用(对无效内存地址的访问)可能导致崩溃。
*/
BOOL sel_isMapped(SEL _Nonnull sel);
/* 向Objective-C运行时系统注册一个方法名。
* @param str 注册的方法的名称
* @return 指定方法的选择器。
* @note 该方法的实现与 sel_registerName() 函数的实现相同。
* @note 在 OS X version 10.0之前,该函数尝试查找映射到给定名称的选择器,如果没有找到选择器,则返回NULL。
* 为了安全起见,更改了这个值,因为观察到这个函数的许多调用者没有检查返回值是否为NULL。
*/
SEL _Nonnull sel_getUid(const char * _Nonnull str);
3、其它函数
3.1、使用库
/* 获取加载的所有 Objective-C frameworks 和动态库的名称。
*/
const char * _Nonnull * _Nonnull objc_copyImageNames(unsigned int * _Nullable outCount);
/* 获取指定类所在的动态库名称。
* @param cls 要查询的类。
* @return 包含此类的库的名称。
*/
const char * _Nullable class_getImageName(Class _Nullable cls);
/* 获取指定库中所有类的名称。
* @param image 查询的 framework 或 library 。
*/
const char * _Nonnull * _Nullable
objc_copyClassNamesForImage(const char * _Nonnull image, unsigned int * _Nullable outCount);
3.2、使用Objective-C语言特性
/* 当遍历过程中检测到改变时,编译器会插入此函数。发生改变时会调用它,如果设置了enumerationMutationHandler,则对其进行设置。如果未设置处理程序,则抛出异常。
* @param obj 被改变的对象。
*/
void objc_enumerationMutation(id _Nonnull obj);
/* 设置当前的变更处理程序。
* @param handler 函数指针指向新的改变处理程序。
*/
void objc_setEnumerationMutationHandler(void (*_Nullable handler)(id _Nonnull ));
/* 设置objc_msgForward() 调用的函数。
* @param fwd 由 objc_msgForward() 跳转到的函数。
* @param fwd_stret 由 objc_msgForward_stret() 跳转到的函数。
*/
void objc_setForwardHandler(void * _Nonnull fwd, void * _Nonnull fwd_stret);
/* 创建一个指向函数的指针,该函数将在调用方法时调用块。
* @param block 实现此方法的块。其签名应该是:method_return_type ^(id self, method_args...)。
* 选择器不是此块的参数;使用Block_copy()复制块。
* @return 调用这个块的IMP;必须用imp_removeBlock() 释放。
*/
IMP _Nonnull imp_implementationWithBlock(id _Nonnull block);
/* 获取与使用 imp_implementationWithBlock() 创建的IMP关联的块。
* @param anImp 调用这个块的IMP。
* @return 由 anImp 调用的块。
*/
id _Nullable imp_getBlock(IMP _Nonnull anImp);
/* 将一个块与使用 imp_implementationWithBlock() 创建的IMP分离,并释放创建的块的副本。
* @param anImp 使用imp_implementationWithBlock() 创建的IMP。
* @return 如果块被成功释放,则为YES;否则为NO 如,块以前可能没有用于创建IMP。
*/
BOOL imp_removeBlock(IMP _Nonnull anImp);
/* 加载由弱指针引用的对象,并在保留和自动释放该对象以确保它保持足够长时间的活动以供调用方使用之后返回该对象。
* 在表达式中使用 __weak 变量的任何地方都可以使用这个函数。
* @param location 弱指针地址
* @return 如果 *location 为nil,则返回 nil。
*/
id _Nullable objc_loadWeak(id _Nullable * _Nonnull location);
/* 这个函数将一个新值存储到 __weak 变量中。
* 它将在 __weak 变量是赋值目标的任何地方使用。
* @param location 弱指针本身的地址
* @param obj 弱指针现在应该指向的新对象
*/
id _Nullable objc_storeWeak(id _Nullable * _Nonnull location, id _Nullable obj);
3.3、Hooks for Swift
/**
* Function type for a hook that intercepts class_getImageName().
*
* @param cls The class whose image name is being looked up.
* @param outImageName On return, the result of the image name lookup.
* @return YES if an image name for this class was found, NO otherwise.
*
* @see class_getImageName
* @see objc_setHook_getImageName
*/
typedef BOOL (*objc_hook_getImageName)(Class _Nonnull cls, const char * _Nullable * _Nonnull outImageName);
/**
* Install a hook for class_getImageName().
*
* @param newValue The hook function to install.
* @param outOldValue The address of a function pointer variable. On return,
* the old hook function is stored in the variable.
*
* @note The store to *outOldValue is thread-safe: the variable will be
* updated before class_getImageName() calls your new hook to read it,
* even if your new hook is called from another thread before this
* setter completes.
* @note The first hook in the chain is the native implementation of
* class_getImageName(). Your hook should call the previous hook for
* classes that you do not recognize.
*
* @see class_getImageName
* @see objc_hook_getImageName
*/
void objc_setHook_getImageName(objc_hook_getImageName _Nonnull newValue,
objc_hook_getImageName _Nullable * _Nonnull outOldValue);
网友评论