美文网首页
OC对象 学习

OC对象 学习

作者: Tony17 | 来源:发表于2020-02-28 09:12 被阅读0次

    前言

    对象是OC的基本单元,由于OC语言的特殊型,所以OC语言的对象或许会有和其他语言不一样的地方,今天来看看OC对象的内部情况。

    OC 对象的本质

    OC 对象可以分为 实例对象(Instance)类对象(Class)元类对象(meta-class) 三种。

    实例对象(Instance)

    1. OC对象实际为结构体,OC特有的isa指针需要占用8个字节;
    2. 因为编译器内存对齐的情况,所以实际需要使用的内存和系统分配的内存有可能存在不一致的情况。系统分配的内存大小都是16字节的倍数;
    3. 如果存在继承的情况,父类和子类的内存是连续的;
    4. 内存中不保存方法列表等信息;
    5. class_getInstanceSize() 获取到实际使用的大小 和 malloc_size() 获取到系统分配的大小

    类对象(Class)

    1. 类对象是唯一的;
    2. 类对象在内存中存储的信息主要是
      • isa 指针
      • superclass 指针
      • 属性信息(@proterty)
      • 对象方法信息(Instance Method)
      • 协议信息(protocol)
      • 成员变量信息(ivar)
      • 类方法信息(Class Method) (null)

    元类对象(meta-class)

    元类对象指的是描述类对象的对象,通过 object_getClass([NSObject class]) 方式获取

    1. 类对象是唯一的;
    2. 类方法放在元类对象中
    3. 元类对象的结构和类对象的结构是一样的
    4. 类对象在内存中存储的信息主要是
      • isa 指针
      • superclass 指针
      • 属性信息(@proterty) (null)
      • 对象方法信息(Instance Method) (null)
      • 协议信息(protocol) (null)
      • 成员变量信息(ivar) (null)
      • 类方法信息(Class Method)

    object_getClass() 传入Instance 返回 Class 、传入Class 返回meta-class

    isa 和 superclass 指向关系

    isa指向关系
    实例对象 -> 类对象 -> 元类对象 -> 基类元类对象 -> 基类元类对象

    superclass指向关系
    类对象 -> 父类对象 -> ... -> 基类对象 -> nil
    元类对象 -> 父类元类对象 -> ... -> 基类元类对象 -> 基类对象

    注意: 调用方法的类对象的时候,如果没有是实现,最终会调用到基类的同名实例对象

    isa

    • arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
    • arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息。
    union isa_t {
        isa_t() { }
            isa_t(uintptr_t value) : bits(value) { }
        
            Class cls;
            uintptr_t bits;
            struct {
                uintptr_t nonpointer        : 1;
                uintptr_t has_assoc         : 1;
                uintptr_t has_cxx_dtor      : 1;
                uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
                uintptr_t magic             : 6;
                uintptr_t weakly_referenced : 1;
                uintptr_t deallocating      : 1;
                uintptr_t has_sidetable_rc  : 1;
                uintptr_t extra_rc          : 19;
            };
    }
    

    各个字段解释:

    • nonpointer
      • 0 代表普通指针,存储着Class、Meta-Class对象的内存地址
      • 1 代表优化过,使用位域存储更多的信息
    • has_assoc
      • 是否有设置过关联对象,如果没有,释放时会更快
    • has_cxx_dtor
      • 是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
    • shiftcls
      • 存储着Class、Meta-Class对象的内存地址信息
    • magic
      • 用于调试时分辨对象是否未完成初始化
    • weakly_referenced
      • 是否有被弱引用指向过,如果没有,释放时会更快
    • deallocating
      • 对象是否正在释放
    • extra_rc
      • 存储引用计数,但是值会-1保存
    • has_sidetable_rc
      • 引用计数起是否过大无法存储在isa
      • 如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
        isa.png

    关键字

    • @synthesize 老版本XCode中指定属性生成成员变量并且创建getter、setter方法,现在不需要手动指定
    • @dynamic 告诉编译器不用自动生成getter、setter的实现,等到运行时再添加方法实现

    super

    • 消息接收者为当前对象,所以 [self class][super class]都返回selfclass(class方法的内部实现是objc_getClass(self))
    • 方法从父类开始查找

    isKindOfClass: 和 isMemberOfClass:

    • isKindOfClass: 用于检查是否是目标类或目标类的子类,如果是类方法的调用方式则判断元类,如果是实例方法调用则判断类,需要注意的是,NSObject元类的父类是NSObject类,所以[obj isKindOfClass:[NSObject class]] 是返回YES
    • isMemberOfClass: 用于检查是否是目标类,如果是类方法的调用方式则判断元类,如果是实例方法调用则判断类

    栈空间分配

    栈空间地址分配是从高到低的方式来分配的,先创建的局部变量是在高地址位置。

    最后

    OC对象中最重要的一个元素就是 isa。可以说他是OC对象的灵魂。

    以上就是本篇的内容,势必会有一些遗漏和错误的地方,欢迎斧正~

    相关文章

      网友评论

          本文标题:OC对象 学习

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