1、Class底层结构分析
在联合体和ISA一篇文章中介绍了对象的Class
方法其实是获取对象的isa.shiftbits
,那么Class
对应的数据结构是什么呢。
从定义中可以看到其实Class就是一个指针,指向一个
objc_class
结构体。objc_class的定义如下:
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
Class getSuperclass() const {
#if __has_feature(ptrauth_calls)
# if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
if (superclass == Nil)
return Nil;
#if SUPERCLASS_SIGNING_TREAT_UNSIGNED_AS_NIL
void *stripped = ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
if ((void *)superclass == stripped) {
void *resigned = ptrauth_sign_unauthenticated(stripped, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
if ((void *)superclass != resigned)
return Nil;
}
#endif
void *result = ptrauth_auth_data((void *)superclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
return (Class)result;
# else
return (Class)ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
# endif
#else
return superclass;
#endif
}
void setSuperclass(Class newSuperclass) {
#if ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ALL
superclass = (Class)ptrauth_sign_unauthenticated((void *)newSuperclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
#else
superclass = newSuperclass;
#endif
}
class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
ASSERT(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
ASSERT(isFuture() || isRealized());
data()->clearFlags(clear);
}
// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
ASSERT(isFuture() || isRealized());
ASSERT((set & clear) == 0);
data()->changeFlags(set, clear);
}
#if FAST_HAS_DEFAULT_RR
bool hasCustomRR() const {
return !bits.getBit(FAST_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.setBits(FAST_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.clearBits(FAST_HAS_DEFAULT_RR);
}
#else
bool hasCustomRR() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.data()->setFlags(RW_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.data()->clearFlags(RW_HAS_DEFAULT_RR);
}
#endif
#if FAST_CACHE_HAS_DEFAULT_AWZ
bool hasCustomAWZ() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
cache.setBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
cache.clearBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
#else
bool hasCustomAWZ() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
bits.data()->setFlags(RW_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
bits.data()->clearFlags(RW_HAS_DEFAULT_AWZ);
}
#endif
#if FAST_CACHE_HAS_DEFAULT_CORE
bool hasCustomCore() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
void setHasDefaultCore() {
return cache.setBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
void setHasCustomCore() {
return cache.clearBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
#else
bool hasCustomCore() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_CORE);
}
void setHasDefaultCore() {
bits.data()->setFlags(RW_HAS_DEFAULT_CORE);
}
void setHasCustomCore() {
bits.data()->clearFlags(RW_HAS_DEFAULT_CORE);
}
#endif
#if FAST_CACHE_HAS_CXX_CTOR
bool hasCxxCtor() {
ASSERT(isRealized());
return cache.getBit(FAST_CACHE_HAS_CXX_CTOR);
}
void setHasCxxCtor() {
cache.setBit(FAST_CACHE_HAS_CXX_CTOR);
}
#else
bool hasCxxCtor() {
ASSERT(isRealized());
return bits.data()->flags & RW_HAS_CXX_CTOR;
}
void setHasCxxCtor() {
bits.data()->setFlags(RW_HAS_CXX_CTOR);
}
#endif
#if FAST_CACHE_HAS_CXX_DTOR
bool hasCxxDtor() {
ASSERT(isRealized());
return cache.getBit(FAST_CACHE_HAS_CXX_DTOR);
}
void setHasCxxDtor() {
cache.setBit(FAST_CACHE_HAS_CXX_DTOR);
}
#else
bool hasCxxDtor() {
ASSERT(isRealized());
return bits.data()->flags & RW_HAS_CXX_DTOR;
}
void setHasCxxDtor() {
bits.data()->setFlags(RW_HAS_CXX_DTOR);
}
#endif
#if FAST_CACHE_REQUIRES_RAW_ISA
bool instancesRequireRawIsa() {
return cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA);
}
void setInstancesRequireRawIsa() {
cache.setBit(FAST_CACHE_REQUIRES_RAW_ISA);
}
#elif SUPPORT_NONPOINTER_ISA
bool instancesRequireRawIsa() {
return bits.data()->flags & RW_REQUIRES_RAW_ISA;
}
void setInstancesRequireRawIsa() {
bits.data()->setFlags(RW_REQUIRES_RAW_ISA);
}
#else
bool instancesRequireRawIsa() {
return true;
}
void setInstancesRequireRawIsa() {
// nothing
}
#endif
void setInstancesRequireRawIsaRecursively(bool inherited = false);
void printInstancesRequireRawIsa(bool inherited);
#if CONFIG_USE_PREOPT_CACHES
bool allowsPreoptCaches() const {
return !(bits.data()->flags & RW_NOPREOPT_CACHE);
}
bool allowsPreoptInlinedSels() const {
return !(bits.data()->flags & RW_NOPREOPT_SELS);
}
void setDisallowPreoptCaches() {
bits.data()->setFlags(RW_NOPREOPT_CACHE | RW_NOPREOPT_SELS);
}
void setDisallowPreoptInlinedSels() {
bits.data()->setFlags(RW_NOPREOPT_SELS);
}
void setDisallowPreoptCachesRecursively(const char *why);
void setDisallowPreoptInlinedSelsRecursively(const char *why);
#else
bool allowsPreoptCaches() const { return false; }
bool allowsPreoptInlinedSels() const { return false; }
void setDisallowPreoptCaches() { }
void setDisallowPreoptInlinedSels() { }
void setDisallowPreoptCachesRecursively(const char *why) { }
void setDisallowPreoptInlinedSelsRecursively(const char *why) { }
#endif
bool canAllocNonpointer() {
ASSERT(!isFuture());
return !instancesRequireRawIsa();
}
bool isSwiftStable() {
return bits.isSwiftStable();
}
bool isSwiftLegacy() {
return bits.isSwiftLegacy();
}
bool isAnySwift() {
return bits.isAnySwift();
}
bool isSwiftStable_ButAllowLegacyForNow() {
return bits.isSwiftStable_ButAllowLegacyForNow();
}
uint32_t swiftClassFlags() {
return *(uint32_t *)(&bits + 1);
}
bool usesSwiftRefcounting() {
if (!isSwiftStable()) return false;
return bool(swiftClassFlags() & 2); //ClassFlags::UsesSwiftRefcounting
}
bool canCallSwiftRR() {
// !hasCustomCore() is being used as a proxy for isInitialized(). All
// classes with Swift refcounting are !hasCustomCore() (unless there are
// category or swizzling shenanigans), but that bit is not set until a
// class is initialized. Checking isInitialized requires an extra
// indirection that we want to avoid on RR fast paths.
//
// In the unlikely event that someone causes a class with Swift
// refcounting to be hasCustomCore(), we'll fall back to sending -retain
// or -release, which is still correct.
return !hasCustomCore() && usesSwiftRefcounting();
}
bool isStubClass() const {
uintptr_t isa = (uintptr_t)isaBits();
return 1 <= isa && isa < 16;
}
// Swift stable ABI built for old deployment targets looks weird.
// The is-legacy bit is set for compatibility with old libobjc.
// We are on a "new" deployment target so we need to rewrite that bit.
// These stable-with-legacy-bit classes are distinguished from real
// legacy classes using another bit in the Swift data
// (ClassFlags::IsSwiftPreStableABI)
bool isUnfixedBackwardDeployingStableSwift() {
// Only classes marked as Swift legacy need apply.
if (!bits.isSwiftLegacy()) return false;
// Check the true legacy vs stable distinguisher.
// The low bit of Swift's ClassFlags is SET for true legacy
// and UNSET for stable pretending to be legacy.
bool isActuallySwiftLegacy = bool(swiftClassFlags() & 1);
return !isActuallySwiftLegacy;
}
void fixupBackwardDeployingStableSwift() {
if (isUnfixedBackwardDeployingStableSwift()) {
// Class really is stable Swift, pretending to be pre-stable.
// Fix its lie.
bits.setIsSwiftStable();
}
}
_objc_swiftMetadataInitializer swiftMetadataInitializer() {
return bits.swiftMetadataInitializer();
}
// Return YES if the class's ivars are managed by ARC,
// or the class is MRC but has ARC-style weak ivars.
bool hasAutomaticIvars() {
return data()->ro()->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
}
// Return YES if the class's ivars are managed by ARC.
bool isARC() {
return data()->ro()->flags & RO_IS_ARC;
}
bool forbidsAssociatedObjects() {
return (data()->flags & RW_FORBIDS_ASSOCIATED_OBJECTS);
}
#if SUPPORT_NONPOINTER_ISA
// Tracked in non-pointer isas; not tracked otherwise
#else
bool instancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif
bool shouldGrowCache() {
return true;
}
void setShouldGrowCache(bool) {
// fixme good or bad for memory use?
}
bool isInitializing() {
return getMeta()->data()->flags & RW_INITIALIZING;
}
void setInitializing() {
ASSERT(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
void setInitialized();
bool isLoadable() {
ASSERT(isRealized());
return true; // any class registered for +load is definitely loadable
}
IMP getLoadMethod();
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() const {
return !isStubClass() && (data()->flags & RW_REALIZED);
}
// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() const {
if (isStubClass())
return false;
return data()->flags & RW_FUTURE;
}
bool isMetaClass() const {
ASSERT_THIS_NOT_NULL;
ASSERT(isRealized());
#if FAST_CACHE_META
return cache.getBit(FAST_CACHE_META);
#else
return data()->flags & RW_META;
#endif
}
// Like isMetaClass, but also valid on un-realized classes
bool isMetaClassMaybeUnrealized() {
static_assert(offsetof(class_rw_t, flags) == offsetof(class_ro_t, flags), "flags alias");
static_assert(RO_META == RW_META, "flags alias");
if (isStubClass())
return false;
return data()->flags & RW_META;
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClassMaybeUnrealized()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return getSuperclass() == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
// If this class does not have a name already, we can ask Swift to construct one for us.
const char *installMangledNameForLazilyNamedClass();
// Get the class's mangled name, or NULL if the class has a lazy
// name that hasn't been created yet.
const char *nonlazyMangledName() const {
return bits.safe_ro()->getName();
}
const char *mangledName() {
// fixme can't assert locks here
ASSERT_THIS_NOT_NULL;
const char *result = nonlazyMangledName();
if (!result) {
// This class lazily instantiates its name. Emplace and
// return it.
result = installMangledNameForLazilyNamedClass();
}
return result;
}
const char *demangledName(bool needsLock);
const char *nameForLogging();
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() const {
ASSERT(isRealized());
return data()->ro()->instanceStart;
}
// Class's instance start rounded up to a pointer-size boundary.
// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart() const {
return word_align(unalignedInstanceStart());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() const {
ASSERT(isRealized());
return data()->ro()->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() const {
return word_align(unalignedInstanceSize());
}
inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
void setInstanceSize(uint32_t newSize) {
ASSERT(isRealized());
ASSERT(data()->flags & RW_REALIZING);
auto ro = data()->ro();
if (newSize != ro->instanceSize) {
ASSERT(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&ro->instanceSize) = newSize;
}
cache.setFastInstanceSize(newSize);
}
void chooseClassArrayIndex();
void setClassArrayIndex(unsigned Idx) {
bits.setClassArrayIndex(Idx);
}
unsigned classArrayIndex() {
return bits.classArrayIndex();
}
}
这是objc4-818.2
版本的定义,其他版本有所不同,但主体结构是一样的。
从objc_class
的定义struct objc_class : objc_object
可以看到objc_class
是继承objc_object
的,在看看objc_object
是的结构:
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
可以看到objc_object
只包含了一个类型为Class
的isa
,所以objc_class
结构体里面也有一个类型为Class
的isa
。这里有点类似链表的结构,但是和链表又有一点不一样,链表中指向节点的类型都是相同的,但是Class
的节点不是相同的,我们可以把它理解的链式结构。
从注释/// Represents an instance of a class.
可以知道objc_object
是一个class
的实例,也就是一个对象。由于objc_class
是继承objc_object
的,所以objc_class
也是一个对象,我们称之为类对象
。
这里也简单提一点我们经常用的id
:
/// A pointer to an instance of a class.
typedef struct objc_object *id;
他就是一个指针,指向objc_object
结构体的指针。从这也可以得知,OC中所有实例对象在底层结构都为objc_object
。
从以上分析我们可以得出以下结论:
-
Class
其实也是一个对象,我们称之为类对象。 - 不管是类对象还是实例对象都有一个变量
isa
2、isa指向
2.1 实例对象
从上面分析得知实例对象里面只有一个isa指针,我们可以一步步来探索:
1、 先利用x/4gx
打印一下对象的内存结构:
通过对
objc_object
的分析,我们知道objc_object
里面就只有一个isa
,所以内存结构的一个8
字节就是isa
指向的内存,也就是0x011d80010000879d
。2、在对象原理二中已经介绍过可以同过
ISA_MASK
这个宏定义来看isa
具体指向那个类:image.png
可以看到
isa
指向的是类MlqqObject
。
3、上一步中我么使用po命令打印了0x011d80010000879d & 0x00007ffffffffff8ULL
的描述信息,我们可以换一个命令p/x
,16进制输出一下其内存地址:
4、既然在第
2
步中,我们已经得到obj
的isa
指向了MlqqObject
,那么我们再利用p/x
打印一下类MlqqObject
的地址:image.png
我们可以看到
MlqqObjec.class
的地址跟我们在第3
步中得到的地址一样。
- 结论实例对象的
isa
是指向类的。
2.2 类对象
我们还可以再接着对MlqqObjec.class
地址进行分析:
1、还是利用x/4gx打印其内存结构:
2、 同理第
1
个8
字节也为其isa
,我们po
输出其isa
:image.png
同样为MlqqObject。
3、我们再打印一下内存地址:
可见图中的两个地址并不相同,也就是说在上一步中得到的
MlqqObject
和2.1
中的第4
步得到的MlqqObject
并不是同一个类。
4、我们可以继续打印上一步中的0x0000000100008770
内存结构:
5、再
po
打印isa
描述信息:image.png
可以看到isa指向NSObject,那是我们理解的NSObject吗,把其内存地址打印出来,然后再把NSObject.class的内存地址打印出来,看看是不是相同:
image.png
可见两个地址并不相同,也就是说这两个东西不是同一个类。
同时可以看到其isa
还是指向0x00007fff88966fe0
。
6、分析一下NSObject.class
内存结构,并查看其isa
:
可见
NSObject.class
的isa
也是指向0x00007fff88966fe0
。
总结以上分析我们可以得到一下关系图:
image.png
3、元类
通过objc_class
的定义我们知道,Class
其实也是一个对象,对象是类的实例化,那么实例化Class
对象的类,我们称之为元类
,元类
的创建和管理都是系统在维护,不需要我们管理。
明确了元类的定义,我们就清楚了这两类就是元类了。
总结:通过上面几步的分析,我们就可以理解那张讲到isa,不得不提的一张图:
image.png
网友评论