这是开头:
由于这段时间公司空闲,准备抓抓手上的技术。由于runtime一直以来都没咋个弄明白过,所以想自己琢磨琢磨,弄弄明白。不会runtime和不咋个了解的老铁们希望我写的东西会对你们有所帮助,文章里边肯定有不足之处,还望技术大大们不吝赐教
一、runtime是什么
首先第一步小白的我要知道runtime是什么,稀里糊涂的我遇到这个问题不知道怎么解释于是乞求度娘解答。。。
度娘给出以下解答:
个人的理解就是oc代码在被执行的过程我们就把他叫做运行时。
但从度娘的口气来看没有单单针对ios来解释runtime,因此我指名道姓的询问度娘“ios runtime”
image.png
度娘不想回答我,于是丢出了一篇大神的博客,于是我点进去,津津有味的啃了起来。大神的文章很详细,我接下来的思路又清除明朗了许多。。[开心到吐舌头🐶]
到此,相信大家对runtime已经有了一个初步的概念。但是,在ios中具体是怎么操作,我们要怎么撸代码呢,那么接着上路吧。
二 、从头到脚认识runtime.h
相信用过runtime的都知道,在调用runtime的方法之前,首先,在所要编写代码的文件下引入runtime.h,如下:
#import <objc/runtime.h>
那么引入后我们要调用啥方法呢(其实我也不知道你要调用啥方法,就我而言,应为目前的工作项目要求的不深且个人能力有限,并没有在实际项目中运用到runtime的东西),那就随便的调用玩一玩。
在此我新建了一个工程,导入#import <objc/runtime.h>后,进入到runtime.h文件。进入一看,可能有些小白要懵逼了,全特么的音哥离席还是c的接口。兄弟们,稳住不要慌,看我三级英语带你们撸过去(装逼不易,还请勿喷😛)
(一)、头部
image.png
就着我的英语水平和开发经验,上面的这一坨申明版权及版本号啥的,让我们能大体的对此文件有个初步认识。但中间出现了一个链接,链接后还附带了一句and read it before using this file. 这绝逼就是开发文档了。于是我开开心心的点开了,我****,居然报错了 image.png
不知道你们打开是啥样,反正我*****。。。
不给我文档,那就凭着一身本事撸下去吧。
在版权声明的下边,导入了一些c库文件,无法进入,但是就是管不住自己的好奇心,于是度娘了一波。结果如下:
*1.stdarg.h是C语言中C标准函数库的头文件,stdarg是由standard(标准) arguments(参数)简化而来,主要目的为让函数能够接收可变参数
2.stddef.h定义了一些标准宏以及类型.
3.Availability.h,这个头文件的作用是判断iOS系统的版本可用性。
4.TargetConditionals.h 作用:会自动配置编译器所要编译的代码将要使用的微处理器指令集、运行系统以及运行时环境。
5.sys/types.h则是在OS_MAC开发中用到的,名称为基本系统数据类型
接下来就是头部重点:
/* Types */
#if !OBJC_TYPES_DEFINED
以下都是结构体类型(不透明类型的个人理解:就是在运行时才会生成,代码内看不见。。)
/// An opaque type that represents a method in a class definition.
(表示类定义中的方法的不透明类型。)(方法)
typedef struct objc_method *Method;
/// An opaque type that represents an instance variable.
(表示实例变量的不透明类型。)(变量)
typedef struct objc_ivar *Ivar;
/// An opaque type that represents a category.
(代表类别的不透明类型。)(类别)
typedef struct objc_category *Category;
/// An opaque type that represents an Objective-C declared property.
(代表Objective-C声明属性的不透明类型。)(属性)
typedef struct objc_property *objc_property_t;
类
struct objc_class {
指向父类或原类
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
父类
Class _Nullable super_class OBJC2_UNAVAILABLE;
类名
const char * _Nonnull name OBJC2_UNAVAILABLE;
版本
long version OBJC2_UNAVAILABLE;
信息
long info OBJC2_UNAVAILABLE;
实例大小
long instance_size OBJC2_UNAVAILABLE;
变量列表
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
方法列表
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
缓存
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
协议列表
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
#endif
#ifdef __OBJC__
协议
@class Protocol;
#else
typedef struct objc_object Protocol;
#endif
/// Defines a method
定义方法时的要素
struct objc_method_description {
名称
SEL _Nullable name; /**< The name of the method */
参数类型
char * _Nullable types; /**< The types of the method arguments */
};
/// Defines a property attribute
定义一个属性的要素
typedef struct {
名称
const char * _Nonnull name; /**< The name of the attribute */
属性值
const char * _Nonnull value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
至此是不是一个,眉清目秀的runtime姑娘已经呈现在你的面前了,你是不是想迫不及待的看看她的曼妙身姿了呢(yy下。。)
(二)、方法接口(身体)
以下方法我将结合代码研究下,篇幅肯定会很长,光说不练不就是假把式么。还得撸撸,不是么。。
object_copy
/**
* Returns a copy of a given object.
*
* @param obj An Objective-C object.
* @param size The size of the object \e obj.
*
* @return A copy of \e obj.
*/
返回给定对象的副本。
*
* @param obj一个Objective-C对象。
* @param size对象的大小\ e obj。
*
* @return \ e obj的副本。
OBJC_EXPORT id _Nullable object_copy(id _Nullable obj, size_t size)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
实例运用:在工程中新建了一个person类继承NSObject,定义了两个属性name,与age。如下:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic, copy)NSString *name;
@property(nonatomic, assign)NSInteger age;
@end
现在就用Person类来操作下runtime下的方法。
注:以上方法由于是在arc模式不可用,需关掉arc
选项改为NO
或者将单一的类兼容MRC(arc模式下找到文件加入-fno-objc-arc,MRC模式下找到加入-fobjc-arc将会支持arc的类)
image.png image.png
由以上方法调用可见object_copy的方法调用后会生成一个新的对象。
object_dispose(非ARC下)
/**
* Frees the memory occupied by a given object.
*
* @param obj An Objective-C object.
*
* @return nil
*/
释放给定对象占用的内存。
*
* @param obj一个Objective-C对象。
*
* @返回nil
OBJC_EXPORT id _Nullable
object_dispose(id _Nullable obj)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
示例:
此时这里会报错,报错原因已经很明确了,应为per已经被释放,per成为了僵尸对象。
报错解决小技巧:这个报错也很常见,通常是一个对象没被初始化或已经释放后调用方法。但是这个报错不会打印日志会让程序猿头疼,怎样才能定位到是那个地方的问题呢,为大家找到了大神的操作
object_getClass
/**
* Returns the class of an object.
*
* @param obj The object you want to inspect.
*
* @return The class object of which \e object is an instance,
* or \c Nil if \e object is \c nil.
*/
返回一个对象的类。
*
* @param obj要检查的对象。
*
* @return其中\ e对象是一个实例的类对象,
*或\ c如果\ e对象是\ n,则为nil。
OBJC_EXPORT Class _Nullable
object_getClass(id _Nullable obj)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
示例:
image.png
object_setClass
/**
* Sets the class of an object.
*
* @param obj The object to modify.
* @param cls A class object.
*
* @return The previous value of \e object's class, or \c Nil if \e object is \c nil.
*/
设置对象的类别。
*
* @param obj要修改的对象。
* @参数cls一个类对象。
*
* @return \ e对象的类的前一个值,或者\ c如果\ e对象是\ c nil,则返回Nil。
OBJC_EXPORT Class _Nullable
object_setClass(id _Nullable obj, Class _Nonnull cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
示例:
image.png
可见per对象所属类被改变,(猜想:oc类型强转时调用了此方法)
object_isClass
/**
* Returns whether an object is a class object.
*
* @param obj An Objective-C object.
*
* @return true if the object is a class or metaclass, false otherwise.
*/
返回一个对象是否是一个类对象。
*
* @param obj一个Objective-C对象。
*
* @如果对象是类或元类,则返回true,否则返回false。
OBJC_EXPORT BOOL
object_isClass(id _Nullable obj)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
示例:
image.png
object_getIvar,
object_setIvar,
object_setIvarWithStrongDefault,
object_setInstanceVariable,
object_setInstanceVariableWithStrongDefault,
object_getInstanceVariable
获取类的实例变量的值和设置实例变量的值(如果Ivar实例变量已知的时候object_getIvar,object_setIvar的效率更高)
/**
* Reads the value of an instance variable in an object.
*
* @param obj The object containing the instance variable whose value you want to read.
* @param ivar The Ivar describing the instance variable whose value you want to read.
*
* @return The value of the instance variable specified by \e ivar, or \c nil if \e object is \c nil.
*
* @note \c object_getIvar is faster than \c object_getInstanceVariable if the Ivar
* for the instance variable is already known.
*/
读取对象中实例变量的值。
*
* @param obj包含要读取其值的实例变量的对象。
* @param ivar Ivar描述了您想要读取其值的实例变量。
*
* @return如果\ e对象是\ c nil,则由\ e ivar指定的实例变量的值或\ c nil。
*
* @note \ c object_getIvar比\ c object_getInstanceVariable快,如果Ivar
*为实例变量已知。
OBJC_EXPORT id _Nullable
object_getIvar(id _Nullable obj, Ivar _Nonnull ivar)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
/**
* Sets the value of an instance variable in an object.
*
* @param obj The object containing the instance variable whose value you want to set.
* @param ivar The Ivar describing the instance variable whose value you want to set.
* @param value The new value for the instance variable.
*
* @note Instance variables with known memory management (such as ARC strong and weak)
* use that memory management. Instance variables with unknown memory management
* are assigned as if they were unsafe_unretained.
* @note \c object_setIvar is faster than \c object_setInstanceVariable if the Ivar
* for the instance variable is already known.
*/
设置对象中实例变量的值。
*
* @param obj包含要设置其值的实例变量的对象。
* @param ivar Ivar描述了你想要设置其值的实例变量。
* @param value实例变量的新值。
*
* @note具有已知内存管理的实例变量(例如ARC强和弱)
*使用内存管理。 具有未知内存管理的实例变量
*被分配为不安全_未保留。
* @note \ c object_setIvar比\ c object_setInstanceVariable快,如果Ivar
*为实例变量已知。
OBJC_EXPORT void
object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
/**
* Sets the value of an instance variable in an object.
*
* @param obj The object containing the instance variable whose value you want to set.
* @param ivar The Ivar describing the instance variable whose value you want to set.
* @param value The new value for the instance variable.
*
* @note Instance variables with known memory management (such as ARC strong and weak)
* use that memory management. Instance variables with unknown memory management
* are assigned as if they were strong.
* @note \c object_setIvar is faster than \c object_setInstanceVariable if the Ivar
* for the instance variable is already known.
*/
设置对象中实例变量的值。
*
* @param obj包含要设置其值的实例变量的对象。
* @param ivar Ivar描述了你想要设置其值的实例变量。
* @param value实例变量的新值。
*
* @note具有已知内存管理的实例变量(例如ARC强和弱)
*使用内存管理。 具有未知内存管理的实例变量
*被分配,如果他们是Strong。
* @note \ c object_setIvar比\ c object_setInstanceVariable快,如果Ivar
*为实例变量已知。
OBJC_EXPORT void
object_setIvarWithStrongDefault(id _Nullable obj, Ivar _Nonnull ivar,
id _Nullable value)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
/**
* Changes the value of an instance variable of a class instance.
*
* @param obj A pointer to an instance of a class. Pass the object containing
* the instance variable whose value you wish to modify.
* @param name A C string. Pass the name of the instance variable whose value you wish to modify.
* @param value The new value for the instance variable.
*
* @return A pointer to the \c Ivar data structure that defines the type and
* name of the instance variable specified by \e name.
*
* @note Instance variables with known memory management (such as ARC strong and weak)
* use that memory management. Instance variables with unknown memory management
* are assigned as if they were unsafe_unretained.
*/
更改类实例的实例变量的值。
*
* @param obj指向一个类的实例的指针。 传递包含的对象
*您希望修改其值的实例变量。
* @param name一个C字符串。 传递您希望修改其值的实例变量的名称。
* @param value实例变量的新值。
*
* @return指向定义类型和的Ivar数据结构的指针
*由\ e名称指定的实例变量的名称。
*
* @note具有已知内存管理的实例变量(例如ARC强和弱)
*使用内存管理。 具有未知内存管理的实例变量
*被分配为unsafe_unretained。
OBJC_EXPORT Ivar _Nullable
object_setInstanceVariable(id _Nullable obj, const char * _Nonnull name,
void * _Nullable value)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
/**
* Changes the value of an instance variable of a class instance.
*
* @param obj A pointer to an instance of a class. Pass the object containing
* the instance variable whose value you wish to modify.
* @param name A C string. Pass the name of the instance variable whose value you wish to modify.
* @param value The new value for the instance variable.
*
* @return A pointer to the \c Ivar data structure that defines the type and
* name of the instance variable specified by \e name.
*
* @note Instance variables with known memory management (such as ARC strong and weak)
* use that memory management. Instance variables with unknown memory management
* are assigned as if they were strong.
*/
更改类实例的实例变量的值。
*
* @param obj指向一个类的实例的指针。 传递包含的对象
*您希望修改其值的实例变量。
* @param name一个C字符串。 传递您希望修改其值的实例变量的名称。
* @param value实例变量的新值。
*
* @return指向定义类型和的Ivar数据结构的指针
*由\ e名称指定的实例变量的名称。
*
* @note具有已知内存管理的实例变量(例如ARC强和弱)
*使用内存管理。 具有未知内存管理的实例变量
*被分配,如果他们是Strong。
OBJC_EXPORT Ivar _Nullable
object_setInstanceVariableWithStrongDefault(id _Nullable obj,
const char * _Nonnull name,
void * _Nullable value)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0)
OBJC_ARC_UNAVAILABLE;
/**
* Obtains the value of an instance variable of a class instance.
*
* @param obj A pointer to an instance of a class. Pass the object containing
* the instance variable whose value you wish to obtain.
* @param name A C string. Pass the name of the instance variable whose value you wish to obtain.
* @param outValue On return, contains a pointer to the value of the instance variable.
*
* @return A pointer to the \c Ivar data structure that defines the type and name of
* the instance variable specified by \e name.
*/
获取类实例的实例变量的值。
*
* @param obj指向一个类的实例的指针。 传递包含的对象
*您希望获取其值的实例变量。
* @param name一个C字符串。 传递您希望获取其值的实例变量的名称。
* @param outValue返回时,包含一个指向实例变量值的指针。
*
* @return指向定义类型和名称的\ c Ivar数据结构的指针
*由\ e名称指定的实例变量。
OBJC_EXPORT Ivar _Nullable
object_getInstanceVariable(id _Nullable obj, const char * _Nonnull name,
void * _Nullable * _Nullable outValue)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
示例如下:
image.png
objc_getClass
objc_getMetaClass
objc_lookUpClass
objc_getRequiredClass
objc_getClassList
objc_copyClassList
返回指定类的类。( objc_getClass与 objc_lookUpClass不同,因为如果类未注册, objc_getClass调用类处理程序回调,然后检查
第二次查看class是否已注册。 objc_lookUpClass不调用类处理程序回调。)
OBJC_EXPORT Class _Nullable
objc_getClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
返回指定类的元类。
OBJC_EXPORT Class _Nullable
objc_getMetaClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
返回指定类的类
OBJC_EXPORT Class _Nullable
objc_lookUpClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
与objc_getClass相同,但如果未找到该类,则会终止该进程。ZeroLink使用该函数,如果没有找到类,则会出现无ZeroLink的编译时链接错误(崩溃)
OBJC_EXPORT Class _Nonnull
objc_getRequiredClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
使用:https://www.jianshu.com/p/bf6c81fc2434
可用于获取工程注册的所有类的总和
OBJC_EXPORT int
objc_getClassList(Class _Nonnull * _Nullable buffer, int bufferCount)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT Class _Nonnull * _Nullable
objc_copyClassList(unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0, 2.0);
class_getName
class_isMetaClass
class_getSuperclass
class_setSuperclass
class_getVersion
class_setVersion
class_getInstanceSize
获取类名
OBJC_EXPORT const char * _Nonnull
class_getName(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
判断是否为元类
OBJC_EXPORT BOOL
class_isMetaClass(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取其父类
OBJC_EXPORT Class _Nullable
class_getSuperclass(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
设置其父类
OBJC_EXPORT Class _Nonnull
class_setSuperclass(Class _Nonnull cls, Class _Nonnull newSuper)
__OSX_DEPRECATED(10.5, 10.5, "not recommended")
__IOS_DEPRECATED(2.0, 2.0, "not recommended")
__TVOS_DEPRECATED(9.0, 9.0, "not recommended")
__WATCHOS_DEPRECATED(1.0, 1.0, "not recommended")
__BRIDGEOS_DEPRECATED(2.0, 2.0, "not recommended");
获取版本号
OBJC_EXPORT int
class_getVersion(Class _Nullable cls)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
设置版本号
OBJC_EXPORT void
class_setVersion(Class _Nullable cls, int version)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
获取类实例的大小
OBJC_EXPORT size_t
class_getInstanceSize(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
简单调用示例如下:
image.png
class_getInstanceVariable
class_getClassVariable
class_copyIvarList
class_getInstanceMethod
class_getClassMethod
class_getMethodImplementation
class_getMethodImplementation_stret
class_respondsToSelector
class_copyMethodList
获取指定实例变量的Ivar
OBJC_EXPORT Ivar _Nullable
class_getInstanceVariable(Class _Nullable cls, const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
获取给定类的指定类变量的Ivar
OBJC_EXPORT Ivar _Nullable
class_getClassVariable(Class _Nullable cls, const char * _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
描述由类声明的实例变量。
OBJC_EXPORT Ivar _Nonnull * _Nullable
class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取实例方法
OBJC_EXPORT Method _Nullable
class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
获取类方法
OBJC_EXPORT Method _Nullable
class_getClassMethod(Class _Nullable cls, SEL _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
获取调用函数指针
OBJC_EXPORT IMP _Nullable
class_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取如果特定的函数将被调用的指针
OBJC_EXPORT IMP _Nullable
class_getMethodImplementation_stret(Class _Nullable cls, SEL _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE;
获取选择器是否响应
OBJC_EXPORT BOOL
class_respondsToSelector(Class _Nullable cls, SEL _Nonnull sel)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取类方法列表
OBJC_EXPORT Method _Nonnull * _Nullable
class_copyMethodList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
简单示例:
image.png
//获取选择器是否响应
NSLog(@"work is responds = %@",@(class_respondsToSelector([Person class], @selector(work))));
NSLog(@"fight is responds = %@",@(class_respondsToSelector([Person class], @selector(fight))));
//获取方法列表
Method *methods = class_copyMethodList([Person class], &count);
for (int i = 0; i < count; i ++) {
NSLog(@"%s", method_getName(methods[i]));
}
打印结果(关于.cxx_destruct方法探究)
Person类添加了fight(未实现)和work的实例方法以及sleep的类方法,class_copyMethodList会找到实现的实例方法以及属性的setter与getter方法,以及ARC下隐藏的释放方法.cxx_destruct
RuntimeTest[2395:86765] work is responds = 1
2018-06-05 10:53:19.226531+0800 RuntimeTest[2395:86765] fight is responds = 0
2018-06-05 10:53:19.226952+0800 RuntimeTest[2395:86765] work
2018-06-05 10:53:19.227174+0800 RuntimeTest[2395:86765] .cxx_destruct
2018-06-05 10:53:19.227507+0800 RuntimeTest[2395:86765] name
2018-06-05 10:53:19.227803+0800 RuntimeTest[2395:86765] setName:
2018-06-05 10:53:19.228017+0800 RuntimeTest[2395:86765] setAge:
2018-06-05 10:53:19.228248+0800 RuntimeTest[2395:86765] age
class_conformsToProtocol
class_copyProtocolList
是否遵守协议
OBJC_EXPORT BOOL
class_conformsToProtocol(Class _Nullable cls, Protocol * _Nullable protocol)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
协议列表
OBJC_EXPORT Protocol * __unsafe_unretained _Nonnull * _Nullable
class_copyProtocolList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
简单示例:
image.png
class_getProperty
class_copyPropertyList
class_getIvarLayout
class_getWeakIvarLayout
获取属性
OBJC_EXPORT objc_property_t _Nullable
class_getProperty(Class _Nullable cls, const char * _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取属性列表
OBJC_EXPORT objc_property_t _Nonnull * _Nullable
class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取IvarLayout
OBJC_EXPORT const uint8_t * _Nullable
class_getIvarLayout(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取week Ivar Lyout
OBJC_EXPORT const uint8_t * _Nullable
class_getWeakIvarLayout(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
简单示例:
image.png
class_addMethod
class_replaceMethod
方法添加
OBJC_EXPORT BOOL
class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
const char * _Nullable types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
方法替换
OBJC_EXPORT IMP _Nullable
class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
const char * _Nullable types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
简单示例:
image.png
tips:由以上可以看出,方法主要由SEL(选择器) + IMP(函数指针)构成
class_addIvar
class_addProtocol
class_addProperty 例子
class_replaceProperty
class_setIvarLayout
class_setWeakIvarLayout
class_createInstance
添加实例变量(此函数只能在objc_allocateClassPair之后和objc_registerClassPair之前调用。类不能是元类。 不支持将实例变量添加到元类。实例变量的最小对齐字节数为1 << align。 实例的最小对齐)
OBJC_EXPORT BOOL
class_addIvar(Class _Nullable cls, const char * _Nonnull name, size_t size,
uint8_t alignment, const char * _Nullable types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
添加协议
OBJC_EXPORT BOOL
class_addProtocol(Class _Nullable cls, Protocol * _Nonnull protocol)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
添加属性
OBJC_EXPORT BOOL
class_addProperty(Class _Nullable cls, const char * _Nonnull name,
const objc_property_attribute_t * _Nullable attributes,
unsigned int attributeCount)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
属性替换
OBJC_EXPORT void
class_replaceProperty(Class _Nullable cls, const char * _Nonnull name,
const objc_property_attribute_t * _Nullable attributes,
unsigned int attributeCount)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
OBJC_EXPORT void
class_setIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
class_setWeakIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
创建实例
OBJC_EXPORT id _Nullable
class_createInstance(Class _Nullable cls, size_t extraBytes)
OBJC_RETURNS_RETAINED
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
objc_constructInstance
objc_destructInstance
objc_allocateClassPair
objc_registerClassPair
objc_duplicateClass
objc_disposeClassPair
创建实例
OBJC_EXPORT id _Nullable
objc_constructInstance(Class _Nullable cls, void * _Nullable bytes)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
销毁实例
OBJC_EXPORT void * _Nullable objc_destructInstance(id _Nullable obj)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
创建一个类
OBJC_EXPORT Class _Nullable
objc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name,
size_t extraBytes)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
类注册
OBJC_EXPORT void
objc_registerClassPair(Class _Nonnull cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
kvo使用 不要自己调用
OBJC_EXPORT Class _Nonnull
objc_duplicateClass(Class _Nonnull original, const char * _Nonnull name,
size_t extraBytes)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
销毁一个类及元类
OBJC_EXPORT void
objc_disposeClassPair(Class _Nonnull cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
method_getName
method_getImplementation
method_getTypeEncoding
method_getNumberOfArguments
method_copyReturnType
method_copyArgumentType
method_getReturnType
method_setImplementation
method_exchangeImplementations
获取方法名
OBJC_EXPORT SEL _Nonnull
method_getName(Method _Nonnull m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取方法的调用的函数指针
OBJC_EXPORT IMP _Nonnull
method_getImplementation(Method _Nonnull m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取方法参数类型
method_getTypeEncoding(Method _Nonnull m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取参数个数
OBJC_EXPORT unsigned int
method_getNumberOfArguments(Method _Nonnull m)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
返回类型描述
OBJC_EXPORT char * _Nonnull
method_copyReturnType(Method _Nonnull m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
参数类型
OBJC_EXPORT char * _Nullable
method_copyArgumentType(Method _Nonnull m, unsigned int index)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
通过返回描述获取返回类型
OBJC_EXPORT void
method_getReturnType(Method _Nonnull m, char * _Nonnull dst, size_t dst_len)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取方法描述
OBJC_EXPORT struct objc_method_description * _Nonnull
method_getDescription(Method _Nonnull m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
设置方法的实现
OBJC_EXPORT IMP _Nonnull
method_setImplementation(Method _Nonnull m, IMP _Nonnull imp)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
交换方法的实现
OBJC_EXPORT void
method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
简单示例:
image.png
ivar_getName
ivar_getTypeEncoding
ivar_getOffset
property_getName
property_getAttributes
property_copyAttributeList
property_copyAttributeValue
protocol_copyProtocolList
获取实例变量名
OBJC_EXPORT const char * _Nullable
ivar_getName(Ivar _Nonnull v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取实例变量的类型
OBJC_EXPORT const char * _Nullable
ivar_getTypeEncoding(Ivar _Nonnull v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取实例变量偏移
OBJC_EXPORT ptrdiff_t
ivar_getOffset(Ivar _Nonnull v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取属性名
OBJC_EXPORT const char * _Nonnull
property_getName(objc_property_t _Nonnull property)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取属性的属性字符串
OBJC_EXPORT const char * _Nullable
property_getAttributes(objc_property_t _Nonnull property)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取属性列表
OBJC_EXPORT objc_property_attribute_t * _Nullable
property_copyAttributeList(objc_property_t _Nonnull property,
unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
属性值
OBJC_EXPORT char * _Nullable
property_copyAttributeValue(objc_property_t _Nonnull property,
const char * _Nonnull attributeName)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
objc_getProtocol
objc_copyProtocolList
protocol_conformsToProtocol
protocol_isEqual
protocol_getName
protocol_getMethodDescription
protocol_copyPropertyList
protocol_copyPropertyList2
objc_allocateProtocol
objc_registerProtocol
protocol_addMethodDescription
通过协议名获取协议
OBJC_EXPORT Protocol * _Nullable
objc_getProtocol(const char * _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
协议列表
OBJC_EXPORT Protocol * __unsafe_unretained _Nonnull * _Nullable
objc_copyProtocolList(unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
判断一个协议是否遵循另一个协议
OBJC_EXPORT BOOL
protocol_conformsToProtocol(Protocol * _Nullable proto,
Protocol * _Nullable other)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
判断两个协议是否相等
OBJC_EXPORT BOOL
protocol_isEqual(Protocol * _Nullable proto, Protocol * _Nullable other)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取协议的名称
OBJC_EXPORT const char * _Nonnull
protocol_getName(Protocol * _Nonnull proto)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取协议方法
OBJC_EXPORT struct objc_method_description
protocol_getMethodDescription(Protocol * _Nonnull proto, SEL _Nonnull aSel,
BOOL isRequiredMethod, BOOL isInstanceMethod)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取协议方法列表
OBJC_EXPORT struct objc_method_description * _Nullable
protocol_copyMethodDescriptionList(Protocol * _Nonnull proto,
BOOL isRequiredMethod,
BOOL isInstanceMethod,
unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取协议属性
OBJC_EXPORT objc_property_t _Nullable
protocol_getProperty(Protocol * _Nonnull proto,
const char * _Nonnull name,
BOOL isRequiredProperty, BOOL isInstanceProperty)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
协议属性列表
OBJC_EXPORT objc_property_t _Nonnull * _Nullable
protocol_copyPropertyList(Protocol * _Nonnull proto,
unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT objc_property_t _Nonnull * _Nullable
protocol_copyPropertyList2(Protocol * _Nonnull proto,
unsigned int * _Nullable outCount,
BOOL isRequiredProperty, BOOL isInstanceProperty)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
协议所遵守的协议
OBJC_EXPORT Protocol * __unsafe_unretained _Nonnull * _Nullable
protocol_copyProtocolList(Protocol * _Nonnull proto,
unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
创建协议
OBJC_EXPORT Protocol * _Nullable
objc_allocateProtocol(const char * _Nonnull name)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
注册协议
OBJC_EXPORT void
objc_registerProtocol(Protocol * _Nonnull proto)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
添加协议方法
OBJC_EXPORT void
protocol_addMethodDescription(Protocol * _Nonnull proto, SEL _Nonnull name,
const char * _Nullable types,
BOOL isRequiredMethod, BOOL isInstanceMethod)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
协议添加
OBJC_EXPORT void
protocol_addProtocol(Protocol * _Nonnull proto, Protocol * _Nonnull addition)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
添加属性
OBJC_EXPORT void
protocol_addProperty(Protocol * _Nonnull proto, const char * _Nonnull name,
const objc_property_attribute_t * _Nullable attributes,
unsigned int attributeCount,
BOOL isRequiredProperty, BOOL isInstanceProperty)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
objc_copyImageNames
class_getImageName
objc_copyClassNamesForImage
获取加载的框架和动态库名
OBJC_EXPORT const char * _Nonnull * _Nonnull
objc_copyImageNames(unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
获取动态库名
OBJC_EXPORT const char * _Nullable
class_getImageName(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
返回库中所有类名
OBJC_EXPORT const char * _Nonnull * _Nullable
objc_copyClassNamesForImage(const char * _Nonnull image,
unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
sel_getName
sel_registerName
sel_isEqual
获取选择器指定的方法名
OBJC_EXPORT const char * _Nonnull
sel_getName(SEL _Nonnull sel)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
注册方法并映射到选择器
OBJC_EXPORT SEL _Nonnull
sel_registerName(const char * _Nonnull str)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
判断两个选择器是否相等
OBJC_EXPORT BOOL
sel_isEqual(SEL _Nonnull lhs, SEL _Nonnull rhs)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
_ objc_enumerationMutation
objc_setEnumerationMutationHandler
objc_setForwardHandler
imp_implementationWithBlock
imp_getBlock
imp_removeBlock
objc_loadWeak
objc_storeWeak_
突变
OBJC_EXPORT void
objc_enumerationMutation(id _Nonnull obj)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
设置突变处理函数
OBJC_EXPORT void
objc_setEnumerationMutationHandler(void (*_Nullable handler)(id _Nonnull ))
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
设置由objc_msgForward调用的函数。
OBJC_EXPORT void
objc_setForwardHandler(void * _Nonnull fwd, void * _Nonnull fwd_stret)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
创建一个指向该块的函数指针
OBJC_EXPORT IMP _Nonnull
imp_implementationWithBlock(id _Nonnull block)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
与使用创建的IMP关联的块
OBJC_EXPORT id _Nullable
imp_getBlock(IMP _Nonnull anImp)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
块移除
OBJC_EXPORT BOOL
imp_removeBlock(IMP _Nonnull anImp)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
加载由弱指针引用的对象(__week时会调用)
OBJC_EXPORT id _Nullable
objc_loadWeak(id _Nullable * _Nonnull location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
存储新值到一个__week修饰的变量中
OBJC_EXPORT id _Nullable
objc_storeWeak(id _Nullable * _Nonnull location, id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
objc_setAssociatedObject
objc_getAssociatedObject
使用给定的键和关联策略设置给定对象的关联值。
OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
返回给定键的给定对象的值。
OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
移除对象的关联
OBJC_EXPORT void
objc_removeAssociatedObjects(id _Nonnull object)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
至此runtime.h中的方法基本上都已简单做了介绍(再往下就是一些参数结构体的定义和过时方法),看了这么久我想大家可能心里已经有一些想法,和一些oc底层实现流程的模糊猜想,
小结:
1.不管是类对象还是类都有一个isa指针,指向其所属的类,例如:Person类继承NSObject其实例对象person的isa指向Person,Person指向Person元类(元类相当于制造类的模子其中包含属性列表和方法列表等)Person元类的isa指向Person父元类(Person元类是Person父元类的实例),直至根元类(根元类的isa指向本身)。
2.属性可以看作是:Ivar+set方法+get方法
3.方法的主要构成为:选择器SEL + 函数指针(IMP)方法的实现主要体现在函数指针所指向的函数
网友评论