OC对象 学习
2020-02-28 本文已影响0人
Tony17
前言
对象是OC的基本单元,由于OC语言的特殊型,所以OC语言的对象或许会有和其他语言不一样的地方,今天来看看OC对象的内部情况。
OC 对象的本质
OC 对象可以分为 实例对象(Instance)
、类对象(Class)
、元类对象(meta-class)
三种。
实例对象(Instance)
- OC对象实际为结构体,OC特有的
isa
指针需要占用8个字节
; - 因为编译器内存对齐的情况,所以实际需要使用的内存和系统分配的内存有可能存在不一致的情况。系统分配的内存大小都是
16字节
的倍数; - 如果存在继承的情况,父类和子类的内存是连续的;
- 内存中不保存方法列表等信息;
-
class_getInstanceSize()
获取到实际使用的大小 和malloc_size()
获取到系统分配的大小
类对象(Class)
- 类对象是唯一的;
- 类对象在内存中存储的信息主要是
- isa 指针
- superclass 指针
- 属性信息(@proterty)
- 对象方法信息(Instance Method)
- 协议信息(protocol)
- 成员变量信息(ivar)
- 类方法信息(Class Method) (null)
元类对象(meta-class)
元类对象指的是描述类对象的对象,通过 object_getClass([NSObject class])
方式获取
- 类对象是唯一的;
- 类方法放在元类对象中
- 元类对象的结构和类对象的结构是一样的
- 类对象在内存中存储的信息主要是
- 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 代表优化过,使用位域存储更多的信息
- 0 代表普通指针,存储着
- has_assoc
- 是否有设置过关联对象,如果没有,释放时会更快
- has_cxx_dtor
- 是否有C++的析构函数(
.cxx_destruct
),如果没有,释放时会更快
- 是否有C++的析构函数(
- 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]
都返回self
的class
(class
方法的内部实现是objc_getClass(self)
) - 方法从父类开始查找
isKindOfClass: 和 isMemberOfClass:
-
isKindOfClass:
用于检查是否是目标类或目标类的子类,如果是类方法的调用方式则判断元类,如果是实例方法调用则判断类,需要注意的是,NSObject
元类的父类是NSObject
类,所以[obj isKindOfClass:[NSObject class]]
是返回YES
的 -
isMemberOfClass:
用于检查是否是目标类,如果是类方法的调用方式则判断元类,如果是实例方法调用则判断类
栈空间分配
栈空间地址分配是从高到低的方式来分配的,先创建的局部变量是在高地址位置。
最后
OC对象中最重要的一个元素就是 isa
。可以说他是OC对象的灵魂。
以上就是本篇的内容,势必会有一些遗漏和错误的地方,欢迎斧正~