OC对象的分类
OC
对象大体上分为3
类
- 实例对象
(instance object)
- 类对象
(class object)
- 元类对象
(meta-class object)
上文中提到的都是实例对象(instance object)

-
获取实例对象的方法就是
alloc
初始化 -
获取类对象的方法有
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
+ (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");
上面两种方法返回的都是类对象,[[NSObject class] class]
返回的对象依然是类对象, 而不是元类对象
runtime
方法:object_getClass
如上图所示, 这些方法返回的NSObject
类对象都指向同一片内存空间
如果要获取元类对象, 只能用object_getClass
, 然后把类对象作为参数传进去, 获取到的就是元类对象.
我们来看看Class
的本质是什么

typedef struct objc_class *Class;
从上面可以知道, Class
的本质就是一个struct objc_class
类型的结构体指针
那么, struct objc_class
又是一个什么东西呢?
在C++
里, 结构体是可以继承的, struct objc_class
是继承自struct objc_object
, 而struct objc_object
就是一个只包含一个成员变量, 即isa
指针的结构体, 所以这个struct objc_object
本质上和NSObject
没有任何区别, 因为NSObject
也是
struct NSObject_IMPL {
Class isa;
};
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
那么, struct objc_class
的数据结构是这样的(截取部分):

可以看到, 成员变量就只有这
4
个
Class isa;
Class superclass;
cache_t cache; // 方法缓存
class_data_bits_t bits; // 用于获取具体的类信息
从这里就可以看出, 类对象里面包含了
-
isa指针
(从struct objc_object
继承而来) superclass指针
-
cache
(以后再说) bits
那么这个bits
又包含了什么玄机呢?

bits
的data
方法, 返回了一个class_rw_t
的列表
具体方法实现如下:

简化下来就是这样
ptrauth_strip(bits,CLASS_DATA_BITS_RW_SIGNING_KEY) & FAST_DATA_MASK;
这就是将bits
通过ptrauth_strip
函数转换成另一个值, 再与上FAST_DATA_MASK
, 这样就拿到了一个指针, 这个指针就指向了struct class_rw_t
这样一个结构体, 那么, struct class_rw_t
结构体里又有什么呢?

那struct class_rw_ext_t
又是什么呢?

可以很清晰地看到, 有以下这些:
- 对象方法
- 属性(的描述)--注意: 并不是属性的值(属性的值存在于实例对象中)
- 协议等
这里面还有一个struct class_ro_t
结构体, 那它里面放了什么呢?

所以, 这些东西都齐了
- 对象方法
- 属性(的描述)--注意: 并不是属性的值(属性的值存在于实例对象中)
- 协议等
- 成员变量(的描述)--注意: 并不是成员变量的值(成员变量的值存在于实例对象中)
而元类, 可以理解为特殊的类对象, 元类对象里也包含了:
-
isa指针
(从struct objc_object
继承而来) -
superclass指针
此外还有 - 类方法
让我们来看看object_getClass
的内部实现
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
很明显是返回的isa
,
那么实例对象的isa指针
指向的是类对象,
类对象的isa
指针指向的是元类对象,
元类对象的isa指针
指向的是基类(NSObject
)的元类对象.
还有一个很容易搞混淆的方法
Class _Nullable
objc_getClass(const char * _Nonnull name)

然后沿着look_up_class
一路查下去, 最后发现了这个方法:

大意是, 有一个哈希表, 存储的是类对象, 可以通过类名, 找到这个类对象, 然后返回出去. 注意, 不会返回元类对象
返回元类对象另有方法, 叫做: objc_getMetaClass

从上图就可以发现, 这两种方法得到的元类对象, 打印的地址是一样的.