Runtime

作者: BigBossZhu | 来源:发表于2019-08-14 17:30 被阅读0次

1. 对象的本质:
数据结构:

objc_object
id(对象)=objc_object
    1. isa_t(共用体)
    2. 关于isa操作的方法
    3. 弱引用相关
    4. 关联对象相关
    5. 内存管理相关
objc_class
Class=objc_class(类也是对象)->继承自objc_object
    1. Class superClass(类对象指向的是父类对象)
    2. cache_t cache(方法缓存结构)
    3. class_data_bits_t bits(关于类定义的变量方法都在此结构中)
isa指针
共用体isa_t
    32或64位01数字,分为指针型的isa(isa的值代表的是Class的地址).非指针型isa(isa的值的部分代表的是Class的地址).
isa指向
    1. 实例对象指向类对象.(实例->Class)
    2. 类对象指向其元类对象.(Class->meteClass)
cache_t
    用于快速查找方法执行函数.
    可增量扩展的哈希表结构
    结构类似数组
    bucket_t结构数组包含(key IMP)
        key:
        IMP:无类型的函数指针
class_data_bits_t
    是对class_rw_t的封装,类的读写信息,分类的方法属性协议.
    代表了类相关读写信息,对class_ro_t的封装(read-only).
    class_ro_t代表类的相关只读信息.
class_rw_t
    1. class_ro_t.
    2. protocols分类中信息.结构是list_array_tt  (二维数组)
    3. properties分类中信息.结构是list_array_tt(二维数组)
    4. methods分类中信息.结构是list_array_tt    (二维数组)
class_ro_t
    1. name(类名)
    2. ivars(成员变量)  (一维数组)
    3. properties   (一维数组)
    4. protocols    (一维数组)
    5. methodList   (一维数组各元素为method_t)
    与上面的区别上面储存的是分类中的内容,因为分类有多个所以是二维数组储存.下面是原理定义类的内容.
method_t结构体.是将函数四要素封装抽象
    1. SEL name;(方法名称)
    2. const char* types(包含函数返回值和参数组合)
    3. IMP imp(无类型的函数指针对应函数体)
types结构:Type Encodings技术
    返回值,参数1,参数2...参数n.(例如 -(void)aMethod对应runtime结构就是v@: v对应返回值void,@对应第一个参数必须是id类型的消息的接收者,:代表SEL代表固定的第二个参数)
整体的数据结构.上面就可以分析了

2. 对象,类对象和元类对象.

    类对象:存储实例方法列表等信息
    元类对象:储存类方法列表等信息
    根类指向nil.对应的是NSObject,
    所有元类对象的isa指针都直接指向根元类对象,含括他自己.根元类对象的superClass指针指向更类对象.

思考:
如果我们调用类方法,没有对应的实现,但是有同名的实例方法实现?会怎么样?为啥?
因为根元类对象的superClass指针指向根类对象,当没有查找到类方法的实现的时候,系统会查找根类中实例方法的实现调用所以不会发生崩溃.

3. 消息传递的机制:
调用的实例方法A.系统会根据当前实例的isa指针找到当前实例的类对象查找实例有实例方法的实现,如果没有会根据superClass的指向逐级查找父类的实例方法.如果最后没有查找到就会走到消息转发流程.类方法类似,只是查找元类对象
首先调用一个方法->缓存方法是否命中->没有命中,根据isa指针找到当前类查找实例方法->没有命中,逐级父类方法查找->消息转发流程.

1. 缓存查找:            在cache_t通过哈希查找(通过给定的值,经过哈希算法找到给定值对应的数组中的索引位置),找到bucket_t从而找到对应方法的IMP实现.
2. 当前类中的查找: 1. 对于已排序好的方法,采用二分法查找.2. 对于未排序好的方法采用一般查找.
3. 父类逐级查找:      通过superClass指针访问父类,判断父类是否为空(是否是NSObject).不为空逐级向上查找.
整体过程,每个查找的具体过程.
4. 消息转发机制:
    resolveInstanceMethod:
    forwardingTargerForSelector:
    methodSignatureForSelector:
    forwardInvocation:
    实例方法:resolveInstanceMethod:
        返回值时BOOL类型的.
        参数是SEL.
        类方法.
        如果返回值时YES或者实现了resolveInstanceMethod相当于告诉系统方法已处理.返回NO会回调forwardingTargerForSelector:
    forwardingTargerForSelector:
        返回值时id
        参数是SEL.
        如果指定转发目标,系统会把消息传递给转发目标.返回nil会调用methodSignatureForSelector:返回方法签名调用forwardInvocation.消息无法处理
    类方法:resolveClassMethod:

method-swizzing:方法交换,修改对应方法的方法实现.
实际使用:添加统计信息.添加报错信息

为一个类动态添加方法:performSelector
可以在消息的转发中动态添加方法的实现:class_addMethod()动态添加.

动态方法解析?@dynamic申明属性在实现中标示成@dynamic,不需要编译器在编译时生成get,和set方法的具体实现,而是get,和set方法我们调用时是在运行时添加.

#import <Foundation/Foundation.h>

@interface Man : NSObject
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSString *sex;
@end
//  Man.m
#import "Man.h"

@implementation Man
@dynamic name, sex;
@end

动态运行时语言将函数决议推迟到运行时.编译时语言在编译期进行函数决议.

相关文章

网友评论

      本文标题:Runtime

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