美文网首页
iOS runtime 之稀里糊涂到有所收获(一)

iOS runtime 之稀里糊涂到有所收获(一)

作者: 那个谁_5207 | 来源:发表于2018-06-07 15:34 被阅读26次

    这是开头:
    由于这段时间公司空闲,准备抓抓手上的技术。由于runtime一直以来都没咋个弄明白过,所以想自己琢磨琢磨,弄弄明白。不会runtime和不咋个了解的老铁们希望我写的东西会对你们有所帮助,文章里边肯定有不足之处,还望技术大大们不吝赐教

    一、runtime是什么
    首先第一步小白的我要知道runtime是什么,稀里糊涂的我遇到这个问题不知道怎么解释于是乞求度娘解答。。。
    度娘给出以下解答:

    image.png
    个人的理解就是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

    image.png

    选项改为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;
    

    示例:

    image.png
    此时这里会报错,报错原因已经很明确了,应为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)方法的实现主要体现在函数指针所指向的函数

    相关文章

      网友评论

          本文标题:iOS runtime 之稀里糊涂到有所收获(一)

          本文链接:https://www.haomeiwen.com/subject/pdjksftx.html